Camkit 树莓派视频传输,使用分析

来源:互联网 发布:淘宝客服话术范文 编辑:程序博客网 时间:2024/06/11 10:27

上网找了一个开源的库,是Camkit 一个开源的C语言库,支持单个摄像头发送RTP包视频流。

具体可以参考github文档:https://git.oschina.net/andyspider/Camkit

自己的好奇,希望在树莓派上使用两个摄像头,参考了库里面的simple_demo代码后,自己写了传输两个摄像头视频流的demo

先讲讲思路,比较简单,首先理由v4l2打开pi上的两个摄像头(需要注意的是,usb摄像头的设备位置会经常变动,有时候是video0 和video1 有时候又是video0 和video1,怎么回事,我也还没弄明白,但是先这样用着,可以用 ls /dev | grep video* 查询一下他们的名字,然后对应修改就可以了)

接着,打开两个udp socket的连接

后面打开convert handle,encode handle,pack handle;

接着设置他们的参数。

到这里,所有准备工作已经做完

接着就是一个loop 开始捕获图片,把捕获的图片转换为YUV420,获取h264 头,打包,发送头,编码转换为YUV420的图片,打包,发送。done


因为这里是两个摄像头,因此就每个摄像头交替完成上述的loop的过程!


下面附上代码(写的菜,不要介意!)


#include <stdio.h>#include <string.h>#include <errno.h>#include <stdlib.h>#include <unistd.h>#include <linux/videodev2.h>#include <pthread.h>#include "camkit.h"#define WIDTH 352#define HEIGHT 288#define FRAMERATE 10// set paramentsU32 vfmt = V4L2_PIX_FMT_YUYV;U32 ofmt = V4L2_PIX_FMT_YUV420;char *deviceOne = "/dev/video2";char *deviceTwo = "/dev/video3";char *oneIp = "192.168.199.219";int onePort = 8888;int twoPort = 8000;struct cvt_handle *cvthandle = NULL;struct enc_handle *enchandle = NULL;struct pac_handle *pachandle = NULL;struct tms_handle *tmshandle = NULL;struct net_handle * getNetParam(char* ip_address,int port){struct net_handle *nethandle = NULL;struct net_param netp;netp.type = UDP;    netp.serip = ip_address;    netp.serport = port;    nethandle = net_open(netp);    if (!nethandle)    {        printf("--- Open network failed\n");    return NULL;    }return nethandle;}int  initParams(){struct cvt_param cvtp;struct enc_param encp;struct pac_param pacp;struct tms_param tmsp;    cvtp.inwidth = WIDTH;cvtp.inheight = HEIGHT;cvtp.inpixfmt = vfmt;cvtp.outwidth = WIDTH;cvtp.outheight = HEIGHT;cvtp.outpixfmt = ofmt;encp.src_picwidth = WIDTH;encp.src_picheight = HEIGHT;encp.enc_picwidth = WIDTH;encp.enc_picheight = HEIGHT;encp.chroma_interleave = 0;encp.fps = FRAMERATE;encp.gop = 12;encp.bitrate = 800;pacp.max_pkt_len = 1400;pacp.ssrc = 1234;    tmsp.startx = 10;tmsp.starty = 10;tmsp.video_width = WIDTH;tmsp.factor = 0;cvthandle = convert_open(cvtp);if (!cvthandle){printf("--- Open convert failed\n");return -1;}enchandle = encode_open(encp);if (!enchandle){printf("--- Open encode failed\n");return -1;}pachandle = pack_open(pacp);if (!pachandle){printf("--- Open pack failed\n");return -1;}tmshandle = timestamp_open(tmsp);if(!tmshandle){printf("--- Open timestamp failde \n");return -1;}return 0;}int openOne(){/* using net handle*/struct net_handle *nethandle = NULL;/* using capture handle*/struct cap_handle *caphandle = NULL;struct cap_handle *caphandleOne = NULL; // first captruestruct cap_handle *caphandleTwo = NULL; // second captruestruct net_handle *nethandleOne = getNetParam(oneIp,onePort); // first ipstruct net_handle *nethandleTwo = getNetParam(oneIp,twoPort); // seconde ip/*set first captrue handle*/    struct cap_param cappOne;    cappOne.dev_name = deviceOne;cappOne.width = WIDTH;cappOne.height = HEIGHT;cappOne.pixfmt = vfmt;cappOne.rate = FRAMERATE;/*set second captrue handle*/struct cap_param cappTwo;cappTwo.dev_name = deviceTwo;cappTwo.width = WIDTH;cappTwo.height = HEIGHT;cappTwo.pixfmt = vfmt;cappTwo.rate = FRAMERATE;caphandleOne = capture_open(cappOne);caphandleTwo = capture_open(cappTwo);if (!caphandleOne || !caphandleTwo){printf("--- Open capture failed\n");return -1;}initParams();// start stream loopint flag = 1;int ret;void *cap_buf, *cvt_buf, *hd_buf, *enc_buf, *pac_buf;int cap_len, cvt_len, hd_len, enc_len, pac_len;enum pic_t ptype;struct timeval  ltime;capture_start(caphandleOne);// !!! need to start capture stream!capture_start(caphandleTwo);//caphandle = caphandleOne;//nethandle = nethandleOne;    gettimeofday(<ime,NULL);while (1){if (flag){caphandle = caphandleOne;nethandle = nethandleOne;flag = 0;//printf("0 start \n");}else{caphandle = caphandleTwo;nethandle = nethandleTwo;flag = 1;//printf("1  start \n");}// 获取一帧图像ret = capture_get_data(caphandle, &cap_buf, &cap_len);if (ret != 0){if (ret < 0)// error{printf("--- capture_get_data failed\n");break;}else// again{usleep(10000);continue;}}if (cap_len <= 0){printf("!!! No capture data  : %d \n", flag);continue;}// else//转换,YUV422=>YUV420, 如果你的摄像头直接支持采集YUV420数据则不需要这一步ret = convert_do(cvthandle, cap_buf, cap_len, &cvt_buf, &cvt_len);if (ret < 0){printf("--- convert_do failed\n");break;}if (cvt_len <= 0){printf("!!! No convert data\n");continue;}// else//加时间戳timestamp_draw(tmshandle,cvt_buf);// fetch h264 headers first!// 第一次取得头 获取h264头,PPS/SPSwhile ((ret = encode_get_headers(enchandle, &hd_buf, &hd_len, &ptype))!= 0){            //fwrite(hd_buf, 1, hd_len, dumpfile);pack_put(pachandle, hd_buf, hd_len);while (pack_get(pachandle, &pac_buf, &pac_len) == 1){//发送头               ret = net_send(nethandle, pac_buf, pac_len);if (ret != pac_len){printf("send pack data failed, size: %d, err: %s\n", pac_len,strerror(errno));}}}//// 编码一帧图像//这个type ret = encode_do(enchandle, cvt_buf, cvt_len, &enc_buf, &enc_len,&ptype);if (ret < 0){printf(" --- encode_do failed  %d \n", flag);break;}if (enc_len <= 0){printf("!!! No encode data\n");continue;}// else        //fwrite(enc_buf, 1, enc_len, dumpfile);// RTP pack and send// // 将编码后的图像送给打包器pack_put(pachandle, enc_buf, enc_len);while (pack_get(pachandle, &pac_buf, &pac_len) == 1)  // 获取一个打包后的RTP包{          ret = net_send(nethandle, pac_buf, pac_len);if (ret != pac_len){printf("send pack failed %d , size: %d, err: %s\n", flag, pac_len,strerror(errno));}}}capture_stop(caphandleOne);capture_stop(caphandleTwo);pack_close(pachandle);encode_close(enchandle);convert_close(cvthandle);timestamp_close(tmshandle);net_close(nethandleOne);net_close(nethandleTwo);return 0;}int main(){openOne();return 0;}




1 0
原创粉丝点击