您的位置:首页 > 其它

V4L2采集YUYV数据—X264编码H264视频实例

2017-11-29 09:29 363 查看
转自: http://blog.csdn.net/li_wen01/article/details/53557949
前几天在网上买个罗技的C270摄像头,它支持YUYV(YUV422)和JPEG数据输出。它规格书上写的是支持HD720P(1280*720像素),在实际的调试过程中,我使用该分辨率会导致数据采集过慢。这里需要注意一下,罗技的摄像头C270在有些虚拟机上使用是有异常的,有些是不能映射到虚拟机上,有些是映射过去操作非常缓慢。因为之前在自己的开发板上调试过YUV420的摄像头,在此基础上改为YUYV数据格式,调试的时候还是遇到不少的问题。

x264库的编译可以见之前博客:http://blog.csdn.net/li_wen01/article/details/53571929

在PC上编译X264,可以直接执行下面三条命令:

./configure --enable-shared

make

make install

下面贴出x264部分的代码:

[objc] view
plain copy

print?

/*=============================================================================

# FileName: h264encoder.c

# Desc: this program aim to get image from USB camera,

# used the V4L2 interface.

# Author: licaibiao

# Version:

#&nbs
4000
p; LastChange: 2017-02-21

=============================================================================*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "./include/h264encoder.h"

int WIDTH = 640;

int HEIGHT = 480;

void compress_begin(Encoder *en, int width, int height) {

en->param = (x264_param_t *) malloc(sizeof(x264_param_t));

en->picture = (x264_picture_t *) malloc(sizeof(x264_picture_t));

x264_param_default(en->param); //set default param

//en->param->rc.i_rc_method = X264_RC_CQP;

// en->param->i_log_level = X264_LOG_NONE;

en->param->i_threads = X264_SYNC_LOOKAHEAD_AUTO;

en->param->i_width = width; //set frame width

en->param->i_height = height; //set frame height

WIDTH = width;

HEIGHT = height;

//en->param->i_frame_total = 0;

//en->param->i_keyint_max = 10;

en->param->rc.i_lookahead = 0;

//en->param->i_bframe = 5;

//en->param->b_open_gop = 0;

//en->param->i_bframe_pyramid = 0;

//en->param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;

//en->param->rc.i_bitrate = 1024 * 10;//rate 10 kbps

en->param->i_fps_num = 30;

en->param->i_fps_den = 1;

en->param->i_csp = X264_CSP_I422;

x264_param_apply_profile(en->param, x264_profile_names[4]);

if ((en->handle = x264_encoder_open(en->param)) == 0) {

return;

}

/* Create a new pic */

x264_picture_alloc(en->picture, X264_CSP_I422, en->param->i_width,

en->param->i_height);

}

int compress_frame(Encoder *en, int type, uint8_t *in, uint8_t *out) {

x264_picture_t pic_out;

int index_y, index_u, index_v;

int num;

int nNal = -1;

int result = 0;

int i = 0;

static long int pts = 0;

uint8_t *p_out = out;

charchar *y = en->picture->img.plane[0];

charchar *u = en->picture->img.plane[1];

charchar *v = en->picture->img.plane[2];

charchar * ptr;

index_y = 0;

index_u = 0;

index_v = 0;

num = WIDTH * HEIGHT * 2 - 4 ;

for(i=0; i<num; i=i+4)

{

*(y + (index_y++)) = *(in + i);

*(u + (index_u++)) = *(in + i + 1);

*(y + (index_y++)) = *(in + i + 2);

*(v + (index_v++)) = *(in + i + 3);

}

switch (type) {

case 0:

en->picture->i_type = X264_TYPE_P;

break;

case 1:

en->picture->i_type = X264_TYPE_IDR;

break;

case 2:

en->picture->i_type = X264_TYPE_I;

break;

default:

en->picture->i_type = X264_TYPE_AUTO;

break;

}

en->picture->i_pts = pts++;

if (x264_encoder_encode(en->handle, &(en->nal), &nNal, en->picture,

&pic_out) < 0) {

return -1;

}

for (i = 0; i < nNal; i++) {

memcpy(p_out, en->nal[i].p_payload, en->nal[i].i_payload);

p_out += en->nal[i].i_payload;

result += en->nal[i].i_payload;

}

return result;

}

void compress_end(Encoder *en) {

if (en->handle) {

x264_encoder_close(en->handle);

}

if (en->picture) {

x264_picture_clean(en->picture);

free(en->picture);

en->picture = 0;

}

if (en->param) {

free(en->param);

en->param = 0;

}

}

上面的代码是配置x264编码器的,有下面几个地方需要特别注意:

(1)CSP参数的配置

[objc] view
plain copy

print?

en->param->i_csp = X264_CSP_I422;

在X264中默认的i_csp值是3,也就是X264_CSP_NV12 的值,如果采用YUYV(422)输入格式,这个值一定需要重新设置,不然会出现错误提示:x264 [error]: Invalid input colorspace 。这是因为在x264内核中他会把输入格式装换为下面三种中的一种:X264_CSP_NV12,X264_CSP_NV16,X264_CSP_I444.转换如下:

[objc] view
plain copy

print?

static int x264_frame_internal_csp( int external_csp )

{

switch( external_csp & X264_CSP_MASK )

{

case X264_CSP_NV12:

case X264_CSP_NV21:

case X264_CSP_I420:

case X264_CSP_YV12:

return X264_CSP_NV12;

case X264_CSP_NV16:

case X264_CSP_I422:

case X264_CSP_YV16:

case X264_CSP_V210:

return X264_CSP_NV16;

case X264_CSP_I444:

case X264_CSP_YV24:

case X264_CSP_BGR:

case X264_CSP_BGRA:

case X264_CSP_RGB:

return X264_CSP_I444;

default:

return X264_CSP_NONE;

}

}

(2)profile类型设置

[objc] view
plain copy

print?

x264_param_apply_profile(en->param, x264_profile_names[4]);

在YUV422中,它不支持baseline,默认设置会提示:x264 [error]: baseline profile doesn't support 4:2:2 可以设置下面的其他参数:

[objc] view
plain copy

print?

x264_profile_names[] = { "baseline", "main", "high", "high10", "high422", "high444", 0 };

(3)图片内存分配

[objc] view
plain copy

print?

x264_picture_alloc(en->picture, X264_CSP_I422, en->param->i_width,

en->param->i_height);

这里的第二个参数一定要与你的输入格式先对应,不然的话会出现内存溢出的错误。因为默认的分配图片内存大小是YUV420的。以640*480 分辨率来举例,YUV420 分配一帧图像的内存是450K,而我们YUV422的数据量是600K。

(4)Y,U,V 数据需要分离

[objc] view
plain copy

print?

for(i=0; i<num; i=i+4)

{

*(y + (index_y++)) = *(in + i);

*(u + (index_u++)) = *(in + i + 1);

*(y + (index_y++)) = *(in + i + 2);

*(v + (index_v++)) = *(in + i + 3);

}

YUYV的数据是交错存储的,因此需要把他们分离出来单独存储,如果这里不做处理,图像就会出现异常。

(5)i_pts 参数需要递增

[objc] view
plain copy

print?

en->picture->i_pts = pts++;

i_pts = pts的参数是需要递增的,不让回出现警告:x264 [warning]: non-strictly-monotonic PTS

完整的编译运行结果如下:

[objc] view
plain copy

print?
1dc36

[root@redhat test]# ls

h264encoder.c include lib main.c Makefile out

[root@redhat test]# make

gcc -g -c -o main.o main.c

gcc -g -c -o h264encoder.o h264encoder.c

gcc -g -o x264_test main.o h264encoder.o -lpthread -lx264 -lm

[root@redhat test]# ls

h264encoder.c h264encoder.o include lib main.c main.o Makefile out x264_test

[root@redhat test]# ./x264_test

camera driver name is : uvcvideo

camera device name is : UVC Camera (046d:0825)

camera bus information: usb-0000:00:1a.0-1.1

n_buffer = 4

x264 [warning]: lookaheadless mb-tree requires intra refresh or infinite keyint

x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX

x264 [info]: profile High 4:2:2, level 3.0, 4:2:2 8-bit

spend time 85.082031 s

x264 [info]: frame I:8 Avg QP:20.27 size: 21592

x264 [info]: frame P:503 Avg QP:21.18 size: 3119

x264 [info]: frame B:1485 Avg QP:22.03 size: 952

x264 [info]: consecutive B-frames: 0.8% 0.0% 0.0% 99.2%

x264 [info]: mb I I16..4: 11.9% 55.2% 32.9%

x264 [info]: mb P I16..4: 0.4% 0.2% 0.1% P16..4: 44.8% 7.9% 8.5% 0.0% 0.0% skip:38.2%

x264 [info]: mb B I16..4: 0.0% 0.0% 0.0% B16..8: 25.9% 0.6% 0.1% direct: 1.7% skip:71.7% L0:51.6% L1:47.0% BI: 1.4%

x264 [info]: 8x8 transform intra:46.7% inter:95.7%

x264 [info]: coded y,uvDC,uvAC intra: 60.5% 87.6% 59.7% inter: 5.7% 23.2% 0.9%

x264 [info]: i16 v,h,dc,p: 4% 8% 1% 87%

x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 16% 39% 12% 3% 5% 4% 10% 4% 7%

x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 24% 41% 8% 3% 4% 3% 8% 3% 4%

x264 [info]: i8c dc,h,v,p: 50% 22% 21% 6%

x264 [info]: Weighted P-Frames: Y:0.2% UV:0.0%

x264 [info]: ref P L0: 40.2% 4.8% 39.3% 15.7%

x264 [info]: ref B L0: 65.6% 20.4% 14.0%

x264 [info]: ref B L1: 91.2% 8.8%

x264 [info]: kb/s:379.47

[root@redhat test]#

这里设置的分辨率是640*480 ,这样采集数据比较快。我编码2000帧数据需要的是大约85s,帧率大约在23fps 。也不知道具体是什么原因导致耗时这么长时间。

视频运行如下:

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