Mjpeg-streamer代码分析.doc_第1页
Mjpeg-streamer代码分析.doc_第2页
Mjpeg-streamer代码分析.doc_第3页
Mjpeg-streamer代码分析.doc_第4页
Mjpeg-streamer代码分析.doc_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

代码分析Mjpeg-streamer程序流程图:main()1参数分析2初始化全局变量global.stop = 0; global.buf = NULL; global.size = 0; global.in.plugin = NULL; /* this mutex and the conditional variable are used to synchronize access to the global picture buffer */3初始化互斥体和条件变量,来同步对global buffer的访问 if( pthread_mutex_init(&global.db, NULL) != 0 ) LOG(could not initialize mutex variablen); closelog(); exit(EXIT_FAILURE); if( pthread_cond_init(&global.db_update, NULL) != 0 ) LOG(could not initialize condition variablen); closelog(); exit(EXIT_FAILURE); 忽略管道断裂信号接受 ctrl +c 中止信号,并关闭系统日志服务的连接打开输入插件,并通过dlopen函数在RTLD_LAZY 指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程使用dlsym获取函数入口地址,使gloabl的输入与动态库相关函数相关联。input_init()打开输出插件并通过dlopen函数,使用dlsym获取函数入口地址,使global的输出与相关函数关联output_init()input_run()开始读取,将图片存放在global buffer。ouput_run()pause()Intput_init()一分配视频数据结构二调用init_videoIn(videoIn, dev, width, height, fps, format,1)进行初始化,参数设置。*dev = /dev/video3, width=640, height=480, fps=5, format=V4L2_PIX_FMT_MJPEG,三 init_v4l2()1 打开设备文件。 int fd=open(/dev/video0,O_RDWR); 2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability 3. 选择视频输入,一个视频设备可以有多个视频输入。VIDIOC_S_INPUT,struct v4l2_input 4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度、帧格式等。 VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format memset(&vd-fmt, 0, sizeof(struct v4l2_format); vd-fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd-fmt.fmt.pix.width = vd-width; vd-fmt.fmt.pix.height = vd-height; vd-fmt.fmt.pix.pixelformat = vd-formatIn; vd-fmt.fmt.pix.field = V4L2_FIELD_ANY; ret = ioctl(vd-fd, VIDIOC_S_FMT, &vd-fmt);5设置帧速率/*set framerate */ struct v4l2_streamparm *setfps; setfps = (struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm); memset(setfps, 0, sizeof(struct v4l2_streamparm); setfps-type = V4L2_BUF_TYPE_VIDEO_CAPTURE; setfps-parm.capture.timeperframe.numerator = 1; setfps-parm.capture.timeperframe.denominator = vd-fps; ret = ioctl(vd-fd, VIDIOC_S_PARM, setfps);6. 向驱动申请帧缓冲,NB_BUFFER=4/* * request buffers */ memset(&vd-rb, 0, sizeof(struct v4l2_requestbuffers); vd-rb.count = NB_BUFFER; vd-rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd-rb.memory = V4L2_MEMORY_MMAP; ret = ioctl(vd-fd, VIDIOC_REQBUFS, &vd-rb);7. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。vd-memi = mmap(0 /* start anywhere */ , vd-buf.length, PROT_READ, MAP_SHARED, vd-fd, vd-buf.m.offset); if (vd-memi = MAP_FAILED) perror(Unable to map buffer); goto fatal; 8. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer ret = ioctl(vd-fd, VIDIOC_QBUF, &vd-buf);四分配一个tempbuffer 来重现图片Input_run()1为global全局变量分配一个buf,pglobal-buf = malloc(videoIn-framesizeIn);2 pthread_create(&cam, 0, cam_thread, NULL);创建cam_thread线程3pthread_detach(cam);Cam_thread()1使用uvcGrab来获取图像信息,若是mjpeg格式存入tmpbuffer若是YUYV格式存入framebuffer。while( !pglobal-stop ) /* grab a frame */if( uvcGrab(videoIn) buf中;若视频格式是MJPEG则memcpy_picture将tmpbuffer中的数据复制到pglobal-bufif (videoIn-formatIn = V4L2_PIX_FMT_YUYV) DBG(compressing framen); pglobal-size = compress_yuyv_to_jpeg(videoIn, pglobal-buf, videoIn-framesizeIn, gquality); else DBG(copying framen); pglobal-size = memcpy_picture(pglobal-buf, videoIn-tmpbuffer, videoIn-buf.bytesused); 3 pthread_cond_broadcast信号,给等待的输出线程发送信号。pthread_cond_broadcast(&pglobal-db_update);uvcGrab()1查看isstreaming是否为0,是0 则开启视频捕获,否则获取出队中的缓冲区的数据if (!vd-isstreaming if (video_enable(vd) goto err;memset(&vd-buf, 0, sizeof(struct v4l2_buffer); vd-buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd-buf.memory = V4L2_MEMORY_MMAP; ret = ioctl(vd-fd, VIDIOC_DQBUF, &vd-buf);switch (vd-formatIn) case V4L2_PIX_FMT_MJPEG: if (vd-buf.bytesused formatIn) case V4L2_PIX_FMT_MJPEG: if (vd-buf.bytesused tmpbuffer, vd-memvd-buf.index, vd-buf.bytesused); if (debug) fprintf(stderr, bytes in used %d n, vd-buf.bytesused); break; case V4L2_PIX_FMT_YUYV: if (vd-buf.bytesused vd-framesizeIn) memcpy (vd-framebuffer, vd-memvd-buf.index, (size_t) vd-framesizeIn); else memcpy (vd-framebuffer, vd-memvd-buf.index, (size_t) vd-buf.bytesused); break; default: goto err; break; 3把可用的缓冲区重新入队,ret = ioctl(vd-fd, VIDIOC_QBUF, &vd-buf);output_http.sooutput_init()output_parameter *param使用param指针填充context server结构体,打印出基本信息Output_run()创建server_thread 服务器线程pthread_create(&(serversid.threadID), NULL, server_thread, &(serversid);pthread_detach(serversid.threadID);server_thread()TCP服务器:1为服务器创建socket套接字2填充addr结构体3bind绑定4listen设置监听套接字5 accept循环接收连接请求6创建线程client_thread线程,来处理此次的客户端连接。Client_thread()1初始化iobuffer 指针iobuf request指针 req init_iobuffer(&iobuf); init_request(&req);2 读取请求 memset(buffer, 0, sizeof(buffer); if ( (cnt = _readline(lcfd.fd, &iobuf, buffer, sizeof(buffer)-1, 5) = -1 ) close(lcfd.fd); return NULL; 3分析请求资源命令,发送相应的内容 /* determine what to deliver */ if ( strstr(buffer, GET /?action=snapshot) != NULL ) req.type = A_SNAPSHOT; else if ( strstr(buffer, GET /?action=stream) != NULL ) req.type = A_STREAM; else if ( strstr(buffer, GET /?action=command) != NULL ) int len;req.type = A_COMMAND; switch ( req.type ) case A_SNAPSHOT: DBG(Request for snapshotn); send_snapshot(lcfd.fd); break; case A_STREAM: DBG(Request for streamn); send_stream(lcfd.fd); break; case A_COMMAND: if ( lcfd.pc-conf.nocommands ) send_error(lcfd.fd, 501, this server is configured to not accept commands); break; command(lcfd.pc-id, lcfd.fd, req.parameter); break; case A_FILE: if ( lcfd.pc-conf.www_folder = NULL ) send_error(lcfd.fd, 501, no www-folder configured); else send_file(lcfd.pc-id, lcfd.fd, req.parameter); break; default: DBG(unknown requestn); send_snapshot1等待新一帧pthread_cond_wait(&pglobal-db_update, &pglobal-db);2将帧数据拷贝到frame中memcpy(frame, pglobal-buf, frame_size);3互斥体解锁pthread_mutex_unlock( &pglobal-db );4 HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文。将http回应 写入buffer中,先发送http状态行和消息包头,发送帧数据,之后释放frame缓存区 /* write the response */ sprintf(buffer, HTTP/1.0 200 OKrn STD_HEADER Content-type: image/jpegrn rn); /* send header and image now */ if( write(fd, buffer, strlen(buffer) 0 ) free(frame); return; write(fd, frame, frame_size); free(frame);send_streamHTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文1 发送回应报头状态行,并返回边界字符串,与上帧图片可以区别开,下一帧图片开始。这是在context type的boundary子属性来指明的。sprintf(buffer, HTTP/1.0 200 OKrn STD_HEADER Content-Type: multipart/x-mixed-replace;boundary= BOUNDARY rn rn - BOUNDARY rn); if ( write(fd, buffer, strlen(buffer) buf, frame_size);3发送类型和长度sprintf(buffer, Content-Type: image/jpegrn Content-Length: %drn rn, frame_size)

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论