基于USB摄像头视频数据采集和利用FFMPEG库函数进行视频数据压缩

来源:互联网 发布:软件绿灯测试概念 编辑:程序博客网 时间:2024/06/11 16:32
  1. 从一篇博客中看到的代码,觉得很有用,暂时没时间研究就先转载保存先。参考http://blog.csdn.net/yakimin/article/details/19284467
  2. 后面可以通过tcp传输等,在pc上或者开发板上把yuv视频解码,然后再把yuv转RGB播放出来。同时之前找了个解码的播放器有源码,可以结合两者实现此功能。链接:

  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5. #include <string.h>  
  6. #include <math.h>  
  7. #include <errno.h>  
  8. #include <fcntl.h>  
  9. #include <unistd.h>  
  10. #include <sys/mman.h>  
  11. #include <sys/ioctl.h>  
  12. #include <sys/stat.h>  
  13. #include <linux/videodev2.h>  
  14. #include <libavcodec/avcodec.h>  
  15. #include <libavformat/avformat.h>  
  16. #include <libavformat/avio.h>  
  17. #include <libavutil/opt.h>  
  18. #include <libswscale/swscale.h>  
  19. #include <libavutil/mathematics.h>  
  20.   
  21. #define VIDEO_WIDTH 640  
  22. #define VIDEO_HEIGHT 480  
  23. #define VIDEO_FORMAT V4L2_PIX_FMT_YUYV  
  24. #define BUFFER_COUNT 4  
  25. #define URL_WRONLY 1  
  26.   
  27. struct fimc_buffer {  
  28.     int length;  
  29.     void *start;  
  30. } framebuf[BUFFER_COUNT];  
  31.   
  32. int fd;  
  33. unsigned char yuv4200[1000000] = { 0 };  
  34. unsigned char yuv4220[1000000] = { 0 };  
  35.   
  36. AVFormatContext* pFormatCtxEnc;  
  37. AVCodecContext* pCodecCtxEnc;  
  38. AVFrame* pFrameEnc;  
  39.   
  40. void register_init();  
  41. int open_device();  
  42. int capability();  
  43. int set_v4l2_format();  
  44. int request_buffers();  
  45. int get_camera_data();  
  46. void unregister_all();  
  47. void video_encode_init();  
  48.   
  49. int yuv422_2_yuv420(unsigned char* yuv420, unsigned char* yuv422, int width,  
  50.         int height);  
  51.   
  52. void register_init() {  
  53.     avcodec_register_all();  
  54.     av_register_all();  
  55.   
  56. }  
  57.   
  58. int open_device() {  
  59.     char camera_device[20];  
  60.     struct stat buf;  
  61.     int i;  
  62.     for (i = 0; i < 10; i++) {  
  63.         sprintf(camera_device, "/dev/video%i", i);  
  64.         if (stat(camera_device, &buf) == 0) {  
  65.             break;  
  66.         }  
  67.   
  68.     }  
  69.     fd = open(camera_device, O_RDWR, 0); //设备以非阻塞方式打开  
  70.     if (fd < 0) {  
  71.         printf("Cannot open camera_device\n");  
  72.         return -1;  
  73.     }  
  74.   
  75. }  
  76.   
  77. int set_v4l2_format() {  
  78.     int ret;  
  79.     struct v4l2_format fmt; //设置视频制式和帧格式  
  80.     memset(&fmt, 0, sizeof(fmt));  
  81.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  82.     fmt.fmt.pix.width = VIDEO_WIDTH;  
  83.     fmt.fmt.pix.height = VIDEO_HEIGHT;  
  84.     fmt.fmt.pix.pixelformat = VIDEO_FORMAT;  
  85.     fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;  
  86.     ret = ioctl(fd, VIDIOC_S_FMT, &fmt);  
  87.     if (ret < 0) {  
  88.         printf("VIDIOC_S_FMT failed\n");  
  89.         return ret;  
  90.     }  
  91.   
  92.     ret = ioctl(fd, VIDIOC_G_FMT, &fmt); //获取视频制式和帧格式的实际值,看是否设置正确  
  93.     if (ret < 0) {  
  94.         printf("VIDIOC_G_FMT failed (%d)/n", ret);  
  95.         return ret;  
  96.     }  
  97.   
  98. }  
  99.   
  100. int request_buffers() {  
  101.     int ret;  
  102.     int i;  
  103.     struct v4l2_requestbuffers reqbuf; //向驱动申请帧缓冲  
  104.     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  105.     reqbuf.memory = V4L2_MEMORY_MMAP;  
  106.     reqbuf.count = BUFFER_COUNT;  
  107.     ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);  
  108.     if (ret < 0) {  
  109.         printf("VIDIOC_REQBUFS failed \n");  
  110.         return ret;  
  111.     }  
  112.   
  113.     struct v4l2_buffer buf; //获取帧缓冲地址  
  114.     for (i = 0; i < BUFFER_COUNT; i++) {  
  115.         buf.index = i;  
  116.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  117.         buf.memory = V4L2_MEMORY_MMAP;  
  118.         ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);  
  119.         if (ret < 0) {  
  120.             printf("VIDIOC_QUERYBUF failed\n");  
  121.             return ret;  
  122.         }  
  123.         framebuf[i].length = buf.length;  
  124.         framebuf[i].start = (char *) mmap(0, buf.length, PROT_READ | PROT_WRITE,  
  125.                 MAP_SHARED, fd, buf.m.offset); //将申请到的帧缓冲映射到用户空间,>就能直接操作采集的帧  
  126.         if (framebuf[i].start == MAP_FAILED) {  
  127.             printf("mmap (%d) failed: %s/n", i, strerror(errno));  
  128.             return -1;  
  129.         }  
  130.   
  131.         ret = ioctl(fd, VIDIOC_QBUF, &buf); //将申请到的帧缓冲全部入队列,以便存放数据  
  132.         if (ret < 0) {  
  133.             printf("VIDIOC_QBUF (%d) failed (%d)/n", i, ret);  
  134.             return -1;  
  135.         }  
  136.   
  137.     }  
  138.   
  139. }  
  140.   
  141. int get_camera_data() {  
  142.   
  143.     int ret;  
  144.     int i, k;  
  145.     struct v4l2_buffer buf; //获取帧缓冲地址  
  146.   
  147.     enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //开始视频采集  
  148.     ret = ioctl(fd, VIDIOC_STREAMON, &type);  
  149.     if (ret < 0) {  
  150.         printf("VIDIOC_STREAMON failed (%d)\n", ret);  
  151.         return ret;  
  152.     }  
  153.   
  154.     video_encode_init();  
  155.     i = 0;  
  156.     while (1) {  
  157.         static int delayFrame = 0;  
  158.         int got_packet = 0;  
  159.         printf("-----------seconds = %d----------\n", ++i);  
  160.         for (k = 0; k < 25; k++) {  
  161.             ret = ioctl(fd, VIDIOC_DQBUF, &buf); //出队列以取得已采集数据的帧缓冲,取得原始数据  
  162.             if (ret < 0) {  
  163.                 printf("VIDIOC_DQBUF failed (%d)/n", ret);  
  164.                 return ret;  
  165.             }  
  166.             strncpy(yuv4220, framebuf[buf.index].start,  
  167.                     framebuf[buf.index].length);  
  168.             yuv422_2_yuv420(yuv4200, yuv4220, 640480);  
  169.   
  170.             av_image_alloc(pFrameEnc->data, pFrameEnc->linesize,  
  171.                     pCodecCtxEnc->width, pCodecCtxEnc->height,  
  172.                     pCodecCtxEnc->pix_fmt, 1);  
  173.             pFrameEnc->data[0] = yuv4200;  
  174.             pFrameEnc->data[1] = pFrameEnc->data[0]  
  175.                     + pCodecCtxEnc->width * pCodecCtxEnc->height;  
  176.             pFrameEnc->data[2] = pFrameEnc->data[1]  
  177.                     + pCodecCtxEnc->width * pCodecCtxEnc->height / 4;  
  178.             pFrameEnc->linesize[0] = pCodecCtxEnc->width;  
  179.             pFrameEnc->linesize[1] = pCodecCtxEnc->width / 2;  
  180.             pFrameEnc->linesize[2] = pCodecCtxEnc->width / 2;  
  181.             pFrameEnc->pts = (k + (i - 1) * 25) * 40;  
  182.             pFrameEnc->width = 640;  
  183.             pFrameEnc->height = 480;  
  184.   
  185.             if (!pFormatCtxEnc->nb_streams) {  
  186.                 printf("output file does not contain any stream\n");  
  187.                 exit(0);  
  188.             }  
  189.             AVPacket pkt;  
  190.             av_init_packet(&pkt);  
  191.             pkt.data = NULL;  
  192.             pkt.size = 0;  
  193.   
  194.             printf("encoding frame %d-------", k);  
  195.             ret = avcodec_encode_video2(pCodecCtxEnc, &pkt, pFrameEnc,  
  196.                     &got_packet);  
  197.             if (ret < 0) {  
  198.                 av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");  
  199.             }  
  200.             if (got_packet) {  
  201.                 printf("output frame %d size = %d\n", k - delayFrame, pkt.size);  
  202.                 ret = av_interleaved_write_frame(pFormatCtxEnc, &pkt);  
  203.                 if (ret != 0) {  
  204.                     fprintf(stderr, "write frame into file is failed\n");  
  205.                 } else {  
  206.                     printf("encode and write one frame success\n");  
  207.                 }  
  208.             } else {  
  209.                 delayFrame++;  
  210.                 printf("no frame output\n");  
  211.             }  
  212.             av_free_packet(&pkt);  
  213.   
  214.             ret = ioctl(fd, VIDIOC_QBUF, &buf); //将缓冲重新入对尾,可以循环采集  
  215.             if (ret < 0) {  
  216.                 printf("VIDIOC_QBUF failed (%d)\n", ret);  
  217.                 return ret;  
  218.             }  
  219.         }  
  220.   
  221.         /* get the delayed frames */  
  222.         for (got_packet = 1; got_packet; k++) {  
  223.             fflush(stdout);  
  224.   
  225.             AVPacket pkt;  
  226.             av_init_packet(&pkt);  
  227.             pkt.data = NULL;  
  228.             pkt.size = 0;  
  229.   
  230.             ret = avcodec_encode_video2(pCodecCtxEnc, &pkt, NULL, &got_packet);  
  231.             if (ret < 0) {  
  232.                 fprintf(stderr, "error encoding frame\n");  
  233.                 exit(1);  
  234.             }  
  235.   
  236.             if (got_packet) {  
  237.                 printf("output delayed frame %3d (size=%5d)\n", k - delayFrame,  
  238.                         pkt.size);  
  239.                 av_interleaved_write_frame(pFormatCtxEnc, &pkt);  
  240.                 av_free_packet(&pkt);  
  241.             }  
  242.         }  
  243.     }  
  244.   
  245.     av_write_trailer(pFormatCtxEnc);  
  246.     if (!(pFormatCtxEnc->flags & AVFMT_NOFILE))  
  247.         avio_close(pFormatCtxEnc->pb);  
  248.   
  249.     for (i = 0; i < BUFFER_COUNT; i++) {  
  250.         munmap(framebuf[i].start, framebuf[i].length); //取消映射,释放内存  
  251.     }  
  252.     close(fd);  
  253.     return 0;  
  254. }  
  255.   
  256. int capability() {  
  257.     int ret;  
  258.     struct v4l2_capability cap;  
  259.     ret = ioctl(fd, VIDIOC_QUERYCAP, &cap); //摄像头主要获取功能  
  260.     if (ret < 0) {  
  261.         printf("VIDIOC_QUERYCAP failed \n");  
  262.         return ret;  
  263.     }  
  264.   
  265. }  
  266.   
  267. int yuv422_2_yuv420(unsigned char* yuv420, unsigned char* yuv422, int width,  
  268.         int height) {  
  269.     int imgSize = width * height * 2;  
  270.     int widthStep422 = width * 2;  
  271.   
  272.     unsigned char* p422 = yuv422;  
  273.     unsigned char* p420y = yuv420;  
  274.     unsigned char* p420u = yuv420 + imgSize / 2;  
  275.     unsigned char* p420v = p420u + imgSize / 8;  
  276.     int i, j;  
  277.     for (i = 0; i < height; i += 2) {  
  278.         p422 = yuv422 + i * widthStep422;  
  279.         for (j = 0; j < widthStep422; j += 4) {  
  280.             *(p420y++) = p422[j];  
  281.             *(p420u++) = p422[j + 1];  
  282.             *(p420y++) = p422[j + 2];  
  283.         }  
  284.         p422 += widthStep422;  
  285.         for (j = 0; j < widthStep422; j += 4) {  
  286.             *(p420y++) = p422[j];  
  287.             *(p420v++) = p422[j + 3];  
  288.             *(p420y++) = p422[j + 2];  
  289.         }  
  290.   
  291.     }  
  292.     return 0;  
  293. }  
  294.   
  295. void unregister_all() {  
  296.     int i;  
  297.     for (i = 0; i < BUFFER_COUNT; i++) {  
  298.         munmap(framebuf[i].start, framebuf[i].length); //取消映射,释放内存  
  299.     }  
  300.     close(fd);  
  301.     printf("Camera test Done.\n");  
  302.   
  303. }  
  304.   
  305. void video_encode_init() {  
  306.   
  307.     char* filename = "./264.flv";  
  308.     AVCodec* pCodecEnc;  
  309.     AVOutputFormat* pOutputFormat;  
  310.     AVStream* video_st;  
  311.   
  312.     int i;  
  313.     int ret;  
  314.   
  315.     av_register_all();  
  316.   
  317.     pOutputFormat = av_guess_format(NULL, filename, NULL);  
  318.     if (pOutputFormat == NULL) {  
  319.         fprintf(stderr, "Could not guess the format from file\n");  
  320.         exit(0);  
  321.     } else {  
  322.         printf("guess the format from file success\n");  
  323.     }  
  324.   
  325.     pFormatCtxEnc = avformat_alloc_context();  
  326.     if (pFormatCtxEnc == NULL) {  
  327.         fprintf(stderr, "could not allocate AVFormatContex\n");  
  328.         exit(0);  
  329.     } else {  
  330.         printf("allocate AVFormatContext success\n");  
  331.     }  
  332.   
  333.     pFormatCtxEnc->oformat = pOutputFormat;  
  334.     sprintf(pFormatCtxEnc->filename, "%s", filename);  
  335.     printf("filename is %s\n", pFormatCtxEnc->filename);  
  336.   
  337.     video_st = avformat_new_stream(pFormatCtxEnc, 0);  
  338.     if (!video_st) {  
  339.         fprintf(stderr, "could not allocate AVstream\n");  
  340.         exit(0);  
  341.     } else {  
  342.         printf("allocate AVstream success\n");  
  343.     }  
  344.     pCodecCtxEnc = video_st->codec;  
  345.     pCodecCtxEnc->codec_id = pOutputFormat->video_codec;  
  346.     pCodecCtxEnc->codec_type = AVMEDIA_TYPE_VIDEO;  
  347.     pCodecCtxEnc->bit_rate = 1000000;  
  348.     pCodecCtxEnc->bit_rate_tolerance = 300000000//表示有多少bit的视频流可以偏移出目前的设定.这里的"设定"是指的cbr或者vbr.  
  349.     pCodecCtxEnc->width = 640;  
  350.     pCodecCtxEnc->height = 480;  
  351.     pCodecCtxEnc->time_base = (AVRational) {1,25};  
  352.     //pCodecCtxEnc->time_base.num = 1;  
  353.     //pCodecCtxEnc->time_base.den = 25;  
  354.     pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;  
  355.     pCodecCtxEnc->gop_size = 10;  
  356.     pCodecCtxEnc->max_b_frames = 0;  
  357.   
  358.     av_opt_set(pCodecCtxEnc->priv_data, "preset""superfast"0);  
  359.     av_opt_set(pCodecCtxEnc->priv_data, "tune""zerolatency"0);  
  360.   
  361.     pCodecCtxEnc->pre_me = 2;  
  362.   
  363.     pCodecCtxEnc->lmin = 10;  
  364.     pCodecCtxEnc->lmax = 50;  
  365.   
  366.     pCodecCtxEnc->qmin = 20;  
  367.     pCodecCtxEnc->qmax = 80;  
  368.     pCodecCtxEnc->qblur = 0.0;  
  369.     pCodecCtxEnc->spatial_cplx_masking = 0.3;  
  370.     pCodecCtxEnc->me_pre_cmp = 2;  
  371.     pCodecCtxEnc->rc_qsquish = 1;  
  372.   
  373.     pCodecCtxEnc->b_quant_factor = 4.9;  
  374.     pCodecCtxEnc->b_quant_offset = 2;  
  375.     pCodecCtxEnc->i_quant_factor = 0.1;  
  376.     pCodecCtxEnc->i_quant_offset = 0.0;  
  377.     pCodecCtxEnc->rc_strategy = 2;  
  378.     pCodecCtxEnc->b_frame_strategy = 0;  
  379.     pCodecCtxEnc->dct_algo = 0;  
  380.     pCodecCtxEnc->lumi_masking = 0.0;  
  381.     pCodecCtxEnc->dark_masking = 0.0;  
  382.   
  383.     if (!strcmp(pFormatCtxEnc->oformat->name, "flv")) {  
  384.         pCodecCtxEnc->flags |= CODEC_FLAG_GLOBAL_HEADER;  
  385.     } else {  
  386.         printf("output format is %s\n", pFormatCtxEnc->oformat->name);  
  387.     }  
  388.   
  389.     pCodecEnc = avcodec_find_encoder(pCodecCtxEnc->codec_id);  
  390.     if (!pCodecEnc) {  
  391.         fprintf(stderr, "could not find suitable video encoder\n");  
  392.         exit(0);  
  393.     } else {  
  394.         printf("find the encoder success\n");  
  395.     }  
  396.   
  397.     if (avcodec_open2(pCodecCtxEnc, pCodecEnc, NULL) < 0) {  
  398.         fprintf(stderr, "could not open video codec\n");  
  399.         exit(0);  
  400.     } else {  
  401.         printf("open the video codec success\n");  
  402.     }  
  403.   
  404.     pFrameEnc = avcodec_alloc_frame();  
  405.     if (pFrameEnc == NULL) {  
  406.         fprintf(stderr, "could not allocate pFrameEnc\n");  
  407.         exit(0);  
  408.     } else {  
  409.         printf("allocate pFrameEnc success\n");  
  410.     }  
  411.   
  412.     ret = avio_open(&pFormatCtxEnc->pb, filename, AVIO_FLAG_WRITE);  
  413.     if (ret < 0) {  
  414.         fprintf(stderr, "could not open '%s': %s\n", filename, av_err2str(ret));  
  415.         exit(0);  
  416.     } else {  
  417.         printf("open filename = %s success\n", filename);  
  418.     }  
  419.   
  420.     ret = avformat_write_header(pFormatCtxEnc, NULL);  
  421.     if (ret < 0) {  
  422.         fprintf(stderr, "error occurred when opening outputfile: %s\n",  
  423.                 av_err2str(ret));  
  424.         exit(0);  
  425.     } else {  
  426.         printf("write the header success\n");  
  427.     }  
  428. }  
  429.   
  430. int main() {  
  431.     register_init();  
  432.     open_device();  
  433.     capability();  
  434.     set_v4l2_format();  
  435.     request_buffers();  
  436.     get_camera_data();  
  437.     unregister_all();  
  438.     return 0;  
  439. }  
0 0
原创粉丝点击