您的位置:首页 > 编程语言 > PHP开发

6410H264编码rtp串流

2016-03-02 16:24 811 查看
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},
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: