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

来源:互联网 发布:js数组get 编辑:程序博客网 时间:2024/05/18 03:49

转自: 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?
  1. /*============================================================================= 
  2. #     FileName: h264encoder.c 
  3. #         Desc: this program aim to get image from USB camera, 
  4. #               used the V4L2 interface. 
  5. #       Author: licaibiao 
  6. #      Version:  
  7. #   LastChange: 2017-02-21  
  8. =============================================================================*/  
  9. #include <stdio.h>  
  10. #include <stdlib.h>  
  11. #include <string.h>  
  12. #include "./include/h264encoder.h"  
  13.   
  14. int WIDTH = 640;  
  15. int HEIGHT = 480;  
  16.   
  17. void compress_begin(Encoder *en, int width, int height) {  
  18.     en->param = (x264_param_t *) malloc(sizeof(x264_param_t));  
  19.     en->picture = (x264_picture_t *) malloc(sizeof(x264_picture_t));  
  20.     x264_param_default(en->param); //set default param  
  21.     //en->param->rc.i_rc_method = X264_RC_CQP;  
  22.     // en->param->i_log_level = X264_LOG_NONE;  
  23.   
  24.     en->param->i_threads  = X264_SYNC_LOOKAHEAD_AUTO;  
  25.     en->param->i_width = width; //set frame width  
  26.     en->param->i_height = height; //set frame height  
  27.     WIDTH = width;  
  28.     HEIGHT = height;  
  29.   
  30.     //en->param->i_frame_total = 0;  
  31.   
  32.     //en->param->i_keyint_max = 10;  
  33.     en->param->rc.i_lookahead = 0;   
  34.     //en->param->i_bframe = 5;   
  35.   
  36.     //en->param->b_open_gop = 0;  
  37.     //en->param->i_bframe_pyramid = 0;  
  38.     //en->param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;  
  39.   
  40.     //en->param->rc.i_bitrate = 1024 * 10;//rate 10 kbps  
  41.     en->param->i_fps_num = 30;   
  42.     en->param->i_fps_den = 1;  
  43.     en->param->i_csp = X264_CSP_I422;  
  44.   
  45.     x264_param_apply_profile(en->param, x264_profile_names[4]);   
  46.   
  47.     if ((en->handle = x264_encoder_open(en->param)) == 0) {  
  48.         return;  
  49.     }  
  50.     /* Create a new pic */  
  51.     x264_picture_alloc(en->picture, X264_CSP_I422, en->param->i_width,  
  52.             en->param->i_height);  
  53. }  
  54.   
  55. int compress_frame(Encoder *en, int type, uint8_t *in, uint8_t *out) {  
  56.     x264_picture_t pic_out;  
  57.     int index_y, index_u, index_v;  
  58.     int num;  
  59.     int nNal = -1;  
  60.     int result = 0;  
  61.     int i = 0;  
  62.     static long int pts = 0;  
  63.     uint8_t *p_out = out;  
  64.     charchar *y = en->picture->img.plane[0];     
  65.     charchar *u = en->picture->img.plane[1];     
  66.     charchar *v = en->picture->img.plane[2];     
  67.     charchar * ptr;  
  68.   
  69.     index_y = 0;  
  70.         index_u = 0;  
  71.         index_v = 0;  
  72.   
  73.         num = WIDTH * HEIGHT * 2 - 4  ;  
  74.   
  75.         for(i=0; i<num; i=i+4)  
  76.         {  
  77.                 *(y + (index_y++)) = *(in + i);  
  78.                 *(u + (index_u++)) = *(in + i + 1);  
  79.                 *(y + (index_y++)) = *(in + i + 2);  
  80.                 *(v + (index_v++)) = *(in + i + 3);  
  81.         }  
  82.   
  83.     switch (type) {  
  84.     case 0:  
  85.         en->picture->i_type = X264_TYPE_P;  
  86.         break;  
  87.     case 1:  
  88.         en->picture->i_type = X264_TYPE_IDR;  
  89.         break;  
  90.     case 2:  
  91.         en->picture->i_type = X264_TYPE_I;  
  92.         break;  
  93.     default:  
  94.         en->picture->i_type = X264_TYPE_AUTO;  
  95.         break;  
  96.     }  
  97.   
  98.     en->picture->i_pts = pts++;  
  99.   
  100.     if (x264_encoder_encode(en->handle, &(en->nal), &nNal, en->picture,  
  101.             &pic_out) < 0) {  
  102.         return -1;  
  103.     }  
  104.   
  105.     for (i = 0; i < nNal; i++) {  
  106.         memcpy(p_out, en->nal[i].p_payload, en->nal[i].i_payload);     
  107.         p_out += en->nal[i].i_payload;                                  
  108.         result += en->nal[i].i_payload;  
  109.     }  
  110.   
  111.     return result;  
  112. }  
  113.   
  114. void compress_end(Encoder *en) {  
  115.     if (en->handle) {  
  116.         x264_encoder_close(en->handle);  
  117.     }  
  118.     if (en->picture) {  
  119.         x264_picture_clean(en->picture);  
  120.         free(en->picture);  
  121.         en->picture = 0;  
  122.     }  
  123.     if (en->param) {  
  124.         free(en->param);  
  125.         en->param = 0;  
  126.     }  
  127. }  

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

(1)CSP参数的配置

[objc] view plain copy
 print?
  1. 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?
  1. static int x264_frame_internal_csp( int external_csp )  
  2. {  
  3.     switch( external_csp & X264_CSP_MASK )  
  4.     {  
  5.         case X264_CSP_NV12:  
  6.         case X264_CSP_NV21:  
  7.         case X264_CSP_I420:  
  8.         case X264_CSP_YV12:  
  9.             return X264_CSP_NV12;  
  10.         case X264_CSP_NV16:  
  11.         case X264_CSP_I422:  
  12.         case X264_CSP_YV16:  
  13.         case X264_CSP_V210:  
  14.             return X264_CSP_NV16;  
  15.         case X264_CSP_I444:  
  16.         case X264_CSP_YV24:  
  17.         case X264_CSP_BGR:  
  18.         case X264_CSP_BGRA:  
  19.         case X264_CSP_RGB:  
  20.             return X264_CSP_I444;  
  21.         default:  
  22.             return X264_CSP_NONE;  
  23.     }  
  24. }  


(2)profile类型设置

[objc] view plain copy
 print?
  1. 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?
  1. x264_profile_names[] = { "baseline""main""high""high10""high422""high444"0 };  


(3)图片内存分配

[objc] view plain copy
 print?
  1. x264_picture_alloc(en->picture, X264_CSP_I422, en->param->i_width,  
  2.             en->param->i_height);  
这里的第二个参数一定要与你的输入格式先对应,不然的话会出现内存溢出的错误。因为默认的分配图片内存大小是YUV420的。以640*480 分辨率来举例,YUV420 分配一帧图像的内存是450K,而我们YUV422的数据量是600K。

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

[objc] view plain copy
 print?
  1. for(i=0; i<num; i=i+4)  
  2.         {  
  3.                 *(y + (index_y++)) = *(in + i);  
  4.                 *(u + (index_u++)) = *(in + i + 1);  
  5.                 *(y + (index_y++)) = *(in + i + 2);  
  6.                 *(v + (index_v++)) = *(in + i + 3);  
  7.         }  
    YUYV的数据是交错存储的,因此需要把他们分离出来单独存储,如果这里不做处理,图像就会出现异常。


(5)i_pts 参数需要递增

[objc] view plain copy
 print?
  1. en->picture->i_pts = pts++;  
    i_pts = pts的参数是需要递增的,不让回出现警告:x264 [warning]: non-strictly-monotonic PTS


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

[objc] view plain copy
 print?
  1. [root@redhat test]# ls  
  2. h264encoder.c  include  lib  main.c  Makefile  out  
  3. [root@redhat test]# make  
  4. gcc -g    -c -o main.o main.c  
  5. gcc -g    -c -o h264encoder.o h264encoder.c  
  6. gcc -g -o x264_test main.o  h264encoder.o -lpthread -lx264 -lm  
  7. [root@redhat test]# ls  
  8. h264encoder.c  h264encoder.o  include  lib  main.c  main.o  Makefile  out  x264_test  
  9. [root@redhat test]# ./x264_test   
  10.   
  11. camera driver name is : uvcvideo  
  12. camera device name is : UVC Camera (046d:0825)  
  13. camera bus information: usb-0000:00:1a.0-1.1  
  14. n_buffer = 4  
  15. x264 [warning]: lookaheadless mb-tree requires intra refresh or infinite keyint  
  16. x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX  
  17. x264 [info]: profile High 4:2:2, level 3.0, 4:2:2 8-bit  
  18. spend time 85.082031 s  
  19. x264 [info]: frame I:8     Avg QP:20.27  size21592  
  20. x264 [info]: frame P:503   Avg QP:21.18  size:  3119  
  21. x264 [info]: frame B:1485  Avg QP:22.03  size:   952  
  22. x264 [info]: consecutive B-frames:  0.8%  0.0%  0.099.2%  
  23. x264 [info]: mb I  I16..411.955.232.9%  
  24. x264 [info]: mb P  I16..4:  0.4%  0.2%  0.1%  P16..444.8%  7.9%  8.5%  0.0%  0.0%    skip:38.2%  
  25. x264 [info]: mb B  I16..4:  0.0%  0.0%  0.0%  B16..825.9%  0.6%  0.1 direct1.7 skip:71.7 L0:51.6% L1:47.0% BI1.4%  
  26. x264 [info]: 8x8 transform intra:46.7% inter:95.7%  
  27. x264 [info]: coded y,uvDC,uvAC intra60.587.659.7% inter5.723.20.9%  
  28. x264 [info]: i16 v,h,dc,p:  4%  8%  187%  
  29. x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 163912%  3%  5%  410%  4%  7%  
  30. x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 2441%  8%  3%  4%  3%  8%  3%  4%  
  31. x264 [info]: i8c dc,h,v,p: 502221%  6%  
  32. x264 [info]: Weighted P-Frames: Y:0.2% UV:0.0%  
  33. x264 [info]: ref P L040.2%  4.839.315.7%  
  34. x264 [info]: ref B L065.620.414.0%  
  35. x264 [info]: ref B L191.2%  8.8%  
  36. x264 [info]: kb/s:379.47  
  37.  [root@redhat test]#   
    这里设置的分辨率是640*480 ,这样采集数据比较快。我编码2000帧数据需要的是大约85s,帧率大约在23fps 。也不知道具体是什么原因导致耗时这么长时间。

视频运行如下:

原创粉丝点击