6410H264编码rtp串流

来源:互联网 发布:网络电视是什么意思 编辑:程序博客网 时间:2024/06/03 07:33

OK6410下的wiif的视频小车——camer h264 rtp

采用6410+ov9650的组合采集视频,给出的demo中ov9650只能输出15帧每秒,百度收索ov9650相关配置找到能正常输出30帧每秒的配置,ok6410提供的mfc中无论怎么配置api都不能达到30fps的采样速度,只有15fps,百度里有人说用mmap方式代替read进行可以加快图像采集速度可是调用VIDIOC_QUERYBUF根本无延时,无法判断什么时候中断读取相机接口,希望有高手点播一下,最后无奈只能去driver修改,最开始发现相机接口的4个buffer在读取数据时不时按照顺序读取只读取了其中两个buffer,所以考虑是否是交错模式和连续模式配置错误,但是都给设置为连续模式后还是只有15fps只读取两个buffer,后来找到在相机接口对应的irq函数s3c_fimc_frame_handler中产生中断控制了读取buffer,逐修改中断函数如下:

,,,,,,,,,,,,,,,,,,,,,,,,

case S3C_FIMC_FLAG_IRQ_X:
dev_dbg(ctrl->dev, "irq flag is x\n");
s3c_fimc_enable_lastirq(ctrl);
s3c_fimc_disable_lastirq(ctrl);
FSET_HANDLE_IRQ(ctrl);
FSET_IRQ_LAST(ctrl);
+++ ret = S3C_FIMC_FRAME_TAKE;
--- ret = S3C_FIMC_FRAME_SKIP;
break;

,,,,,,,,,,,,,,,,,,,,,,,,

修改后能够正确采集到30fps的图像,后面附有30fps采集压缩程序,修改自自带的Multmedia_DD。在移植后的vlc中找到读取h264文件的入口(file.c),修改读取文件为读取h264压缩后的数据,由于不懂vlc如何加入c文件编译,所以将所有函数都放在了file.c文件中。这个过程比较多报错所以折腾了很久,h264压缩和采集需要建立新线程处理,为file.c中的fileread函数提供数据,线程之间通信我建立了一个环形buffer进行视频数据的读取。vlc因为默认采用25fps进行解复用,所以修改modules/demux/mpeg/h264.c文件:

,,,,,,,,,,,,,,,,,,,,,,,,

p_demux->pf_control= Control;

p_demux->p_sys     = p_sys = malloc( sizeof( demux_sys_t ) );

p_sys->p_es        = NULL;

p_sys->i_dts       = 0;

p_sys->f_fps       = 29.988;//修改为ov9650输出帧率:29.988

,,,,,,,,,,,,,,,,,,,,,,,,

经过各种折腾终于在电脑端用vlc播放出来了。rtp视频虽然能正常播放了,但还是有几个问题:

1、6410的camera接口输出24Mhz时钟不精准,是不是导致输出30帧率不准确的主要原因?虽然9650里面有微调帧率的寄存器0x92 0x93 0x2a 0x2b。但是我只能调整到29.988。

2、在rtp播放过程中vlc会出现:

main input error: ES_OUT_SET_(GROUP_)PCR  is called too late (pts_delay increased to 1000 ms)

main mux warning: late buffer for mux input

两种输出,这是否是因为6410产生h264数据包的时间戳有问题引起的?


总结:

ov9650输出帧率、h264硬件压缩帧率和vlc相关帧率设置都会引起rtp传输时产生问题:a、内存不断增加,并且播放越久延时越大;b、vlc不停的输出PCR  is called too late和late buffer for mux input,导致视频不连续。6410设置帧率应该乘以该帧率的一倍!不然录制的视频播放速度很快!


采集压缩程序:

/* Main Process(Camera previewing) */

int Forlinx_Test_Cam_Encoding(int argc, char **argv, int lcdnum) {
int ret, start, found = 0;
int k_id;
unsigned int addr = 0;
char rgb_for_preview[LCD_WIDTH_MAX * LCD_HEIGHT_MAX * 4]; // MAX

struct v4l2_capability cap;
struct v4l2_input chan;
struct v4l2_framebuffer preview;
struct v4l2_pix_format preview_fmt;
struct v4l2_format codec_fmt;

pp_params pp_param;
int pp_fd;

g_LCD_Width = lcdsize[lcdnum][0];
g_LCD_Height = lcdsize[lcdnum][1];

// source picture width and height must be a multiple of 16 in codecing
codec_Width = g_LCD_Width / 16 * 16;
codec_Height = g_LCD_Height / 16 * 16;

g_YUV_Frame_Buffer_Size = (codec_Width * codec_Height) + (codec_Width
* codec_Height) / 2;

/* Camera codec initialization */
if ((cam_c_fp = cam_c_init()) < 0)
exit_from_app();
signal_ctrl_c();

#if 1
/* Codec set */
/* Get capability */
ret = ioctl(cam_c_fp, VIDIOC_QUERYCAP, &cap);
if (ret < 0) {
printf("V4L2 : ioctl on VIDIOC_QUERYCAP failled\n");
exit(1);
}

/* Check the type - preview(OVERLAY) */
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
printf("V4L2 : Can not capture(V4L2_CAP_VIDEO_CAPTURE is false)\n");
exit(1);
}

/* Set format */
codec_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
codec_fmt.fmt.pix.width = codec_Width;//LCD_WIDTH;
codec_fmt.fmt.pix.height = codec_Height; //LCD_HEIGHT;
codec_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
codec_fmt.fmt.pix.priv = V4L2_FMT_OUT; // must set

ret = ioctl(cam_c_fp, VIDIOC_S_FMT, &codec_fmt);
if (ret < 0) {
printf("V4L2 : ioctl on VIDIOC_S_FMT failled\n");
exit(1);
}

ret = ioctl(cam_c_fp, VIDIOC_OVERLAY, &codec_start);
if (ret < 0) {
printf("V4L2 : ioctl on VIDIOC_OVERLAY failed\n");
exit(1);
}
codec_reqbuffer.count = 4;
codec_reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
codec_reqbuffer.memory = V4L2_MEMORY_MMAP;
ret = ioctl(cam_c_fp, VIDIOC_REQBUFS, &codec_reqbuffer);
if (ret < 0) {
printf("V4L2 : ioctl on VIDIOC_DQBUF failled\n");
exit(1);
}
printf("codec_reqbuffer.count : %d\n", codec_reqbuffer.count);
VideoBuffer*          buffers = calloc( codec_reqbuffer.count, sizeof(*buffers) );
struct v4l2_buffer    buf;
int numBufs;
for (numBufs = 0; numBufs < codec_reqbuffer.count; numBufs++) {
   memset( &buf, 0, sizeof(buf) );
   buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   buf.memory = V4L2_MEMORY_MMAP;
   buf.index = numBufs;
   printf("buf.type %d, buf.memory %d, buf.index%d\n", buf.type, buf.memory,buf.index);
   // 读取缓存
   if (ioctl(cam_c_fp, VIDIOC_QUERYBUF, &buf) == -1) {
    printf("VIDIOC_QUERYBUF err\n");
       return -1;
   }
   buffers[numBufs].length = buf.length;
   // 转换成相对地址
   buffers[numBufs].start = mmap(NULL, buf.length,
       PROT_READ | PROT_WRITE,
       MAP_SHARED,
       cam_c_fp, buf.m.offset);
   if (buffers[numBufs].start == MAP_FAILED) {
    printf("MAP_FAILED\n");
       return -1;
   }
   // 放入缓存队列
   if (ioctl(cam_c_fp, VIDIOC_QBUF, &buf) == -1) {
    printf("VIDIOC_QBUF err\n");
       return -1;
   }
}
#endif
printf("\n[8. Camera preview & MFC encoding]\n");
printf("Forlinx Embedded, %s\n", VERSION);
printf("Using IP          : MFC, Post processor, LCD, Camera\n");
printf("Display size      : (%dx%d)\n", g_LCD_Width, g_LCD_Height);


/* Encoding and decoding threads creation */
k_id = pthread_create(&pth, 0, (void *) &encoding_thread, 0);

while (1) {
if (finished)
break;
sleep(1);//liu
}
pthread_join(pth, NULL);
finished = 0;
exit_from_app();
return 0;
}

/***************** Encoding Thread *****************/
void encoding_thread(void) {
char file_name[100];
int yuv_cnt = 0;
int start, ret;
int frame_num = YUV_FRAME_NUM;
int key;
unsigned char g_yuv[YUV_FRAME_BUFFER_SIZE_MAX];
unsigned char *encoded_buf;
long encoded_size;
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=0;

printf("\ne : Encoding\n");
printf("x : Exit\n");
printf("Select ==> ");
while (1) {
key = getchar();//liu
if (key == 'e')
encoding_flag = TRUE;
else if (key == 'x') {
finished = 1;
pthread_exit(0);
}
if (encoding_flag == TRUE) {
pthread_mutex_lock(&mutex);
handle = mfc_encoder_init(codec_Width, codec_Height, 30, 1000, 30);
sprintf(&file_name[0], "Cam_encoding_%dx%d-%d.264", codec_Width,
codec_Height, ++film_cnt);
printf("Name of encoded file : Cam_encoding_%dx%d-%d.264\n",
codec_Width, codec_Height, film_cnt);
fflush(stdout);

/* file create/open, note to "wb" */
encoded_fp = fopen(&file_name[0], "wb");
if (!encoded_fp) {
perror(&file_name[0]);
}

/* Codec start */
start = 1;
ret = ioctl(cam_c_fp, VIDIOC_STREAMON, &start);
if (ret < 0) {
printf("V4L2 : ioctl on VIDIOC_STREAMON failed\n");
exit(1);
}
struct timeval t_start, t_end;
long cost_time = 0;
for (yuv_cnt = 0; yuv_cnt < frame_num; yuv_cnt++) {
frame_count++;
buf.index=0;
gettimeofday(&t_start, NULL);
#if 1
/* read from camera device */
if (read(cam_c_fp, g_yuv, g_YUV_Frame_Buffer_Size) < 0) {
perror("read()");
}
#endif
#if 1
ret = ioctl(cam_c_fp, VIDIOC_DQBUF, &buf);
if (ret < 0) {
printf("V4L2 : ioctl on VIDIOC_DQBUF failled\n");
exit(1);
}
#endif
#if 1
if(frame_count == 1)
encoded_buf = mfc_encoder_exe(handle, g_yuv, g_YUV_Frame_Buffer_Size, 1, &encoded_size);
else
encoded_buf = mfc_encoder_exe(handle, g_yuv, g_YUV_Frame_Buffer_Size, 0, &encoded_size);
#endif
gettimeofday(&t_end, NULL);
cost_time = t_end.tv_usec - t_start.tv_usec;

printf("Cost a time: %ld us\n", cost_time);
//重新放入缓存队列
if (ioctl(cam_c_fp, VIDIOC_QBUF, &buf) == -1) {
printf("VIDIOC_QBUF err\n");
   return -1;
}
fwrite(encoded_buf, 1, encoded_size, encoded_fp);
}
frame_count = 0;


/* Codec stop */
start = 0;
ret = ioctl(cam_c_fp, VIDIOC_STREAMOFF, &start);
if (ret < 0) {
printf("V4L2 : ioctl on VIDIOC_STREAMOFF failed\n");
exit(1);
}

printf("100 frames were encoded\n");
printf("\nSelect ==> ");

mfc_encoder_free(handle);
fclose(encoded_fp);
encoding_flag = FALSE;
pthread_mutex_unlock(&mutex);
}
}
}



————————ov9650 配置vga 30fps————————

        /* OV9650intialization parameter table for VGA application */
        {0x12, 0x80},       // Camera Soft reset. Self cleared after reset.
        {CHIP_DELAY, 10},
        {0x11,0x80},{0x6a,0x3e},{0x3b,0x09},{0x13,0xe0},{0x01,0x80},{0x02,0x80},{0x00,0x00},{0x10,0x00},
       {0x13,0xe5},{0x39,0x43},{0x38,0x12},{0x37,0x00},{0x35,0x91},{0x0e,0xa0},{0x1e,0x04},{0xA8,0x80},
       {0x12,0x40},{0x04,0x40},{0x0c,0x04},{0x0d,0x80},{0x18,0xc6},{0x17,0x26},{0x32,0xad},{0x03,0x00},
       {0x1a,0x3d},{0x19,0x01},{0x3f,0xa6},{0x14,0x2e},{0x15,0x10},{0x41,0x02},{0x42,0x08},{0x1b,0x00},
       {0x16,0x06},{0x33,0xe2},{0x34,0xbf},{0x96,0x04},{0x3a,0x00},{0x8e,0x00},{0x3c,0x77},{0x8B,0x06},
       {0x94,0x88},{0x95,0x88},{0x40,0xc1},{0x29,0x3f},{0x0f,0x42},{0x3d,0x92},{0x69,0x40},{0x5C,0xb9},
       {0x5D,0x96},{0x5E,0x10},{0x59,0xc0},{0x5A,0xaf},{0x5B,0x55},{0x43,0xf0},{0x44,0x10},{0x45,0x68},
       {0x46,0x96},{0x47,0x60},{0x48,0x80},{0x5F,0xe0},{0x60,0x8c},{0x61,0x20},{0xa5,0xd9},{0xa4,0x74},
       {0x8d,0x02},{0x13,0xe7},{0x4f,0x3a},{0x50,0x3d},{0x51,0x03},{0x52,0x12},{0x53,0x26},{0x54,0x38},
       {0x55,0x40},{0x56,0x40},{0x57,0x40},{0x58,0x0d},{0x8C,0x23},{0x3E,0x02},{0xa9,0xb8},{0xaa,0x92},
       {0xab,0x0a},{0x8f,0xdf},{0x90,0x00},{0x91,0x00},{0x9f,0x00},{0xa0,0x00},{0x3A,0x01},{0x24,0x70},
       {0x25,0x64},{0x26,0xc3},
{0x2a,0x00},{0x2b,0x00},
{0x92,0x04},//liu
{0x93,0x00},//liu
{0x6c,0x40},{0x6d,0x30},{0x6e,0x4b},{0x6f,0x60},
        {0x70,0x70},{0x71,0x70},{0x72,0x70},{0x73,0x70},{0x74,0x60},{0x75,0x60},{0x76,0x50},{0x77,0x48},
       {0x78,0x3a},{0x79,0x2e},{0x7a,0x28},{0x7b,0x22},{0x7c,0x04},{0x7d,0x07},{0x7e,0x10},{0x7f,0x28},
       {0x80,0x36},{0x81,0x44},{0x82,0x52},{0x83,0x60},{0x84,0x6c},{0x85,0x78},{0x86,0x8c},{0x87,0x9e},
       {0x88,0xbb},{0x89,0xd2},{0x8a,0xe6},

0 0