应用SDL及GTK_实现视频多路回放

合集下载

基于DirectShow的客户端实时视频流回放技术

基于DirectShow的客户端实时视频流回放技术

d, t ) e r lr  ̄ fe 等。过滤器通过向文件读写、 ei 修改数据和显示数据到输 出设备上来操作流媒体。为了完成整个 任务 。 必须要将所有的过滤器 F t 连接起来 , 3 ir l e 这 种过滤器组成了过滤器图表结构 , 如图 I 所示。
Die th w r cS o
术, 避开了复杂的视频流解压算法 , 具有较好的通用性和可移植性。
1 Drc hw 简 介 i t o eS
M ic hw的设计 目 SD eSo rt 标是: 隔离数据传输 、 硬件兼容、 流同步等底层处理, 使客户能够轻轻松松地创建 W n w 应用平台上的多媒体应用程序[。它对媒体数据的处理采用流媒体( uie a t ) i os d ¨ M l d 咖 的方式, t is m 在应用 中大大的减少了编程的复杂程度, 同时又可以自 动协商从数据源到应用的转换 , 口 流接 提供了统一的、 可以预测 的数据存取的控制方法, 这样应用程序在播放媒体数据时不需要考虑它最初的来源和格式。
V I 2 . o. 8N 1 o
Ma .2 o r 06
基 于 Drc hw的客户 端 i to eS 实 时视频 流 回放 技 术
刘 琼 , 慧灿 周
( 湖南文理学院 计算机科学系 。 湖南 常德 450 ) 103

要: 介绍 了Dr t o 术的原理并 以 M E i c hw技 eS P G一1视频流解 码回放为例 , 详细说 明了 Ft Gah的构建 与实现方法。 ir r l e p 文献标识码 : A 文章编号 :6 1 2 120 )1 0 1 3 17 —03 (060 —06 —0
维普资讯
在过滤器图表结构中, 源过滤器用来从数据源劳敢数据 , 并将数据传送到过滤器 图表中, 这里的数据

只需四行代码即可简单实现SDL嵌入MFC播放视频和图片2014.2.18

只需四行代码即可简单实现SDL嵌入MFC播放视频和图片2014.2.18

纠结半个多月的SDL嵌入MFC的工作终于实现了,蛋疼的是看了那么多代码,找了好多程序,结果实现只需几行代码!!!我们还是低估SDL了,大家都想错路了。

百度看了好多人写的文章,虽然只有几篇介绍SDL嵌入MFC的文章,但是大致都出自一人之手,都是改写winmain,SDL_main等函数的,我第一次看的时候就感觉改了那么多东西,但是关联都不是很大,只知道要获取控件的ID(你想在哪个控件上播放),MFC的原理就是这样,就是获取各种ID。

第一次实现那位仁兄的显示图片到SDI的功能的时候(我是用DLG实现的),我没发觉为什么显示的时候覆盖了整个对话框,因为要实现播放视频,当时还没调通显示视频的部分,而他代码里只有DrawPict这个函数,所以就没注意。

知道今天当我把视频播放,语音播放功能都实现后回头看的时候才发现,原来最重要的就是那么几行。

好了,不瞎扯了,大家可能着急了,到底怎么实现的SDL播放画面嵌入MFC控件中去的。

下面是代码片段:SDL_Event event;static struct SwsContext *img_convert_ctx;char * filePath="c:/test.mp4";/************************************************************************//* 测试SDL窗口显示到mfc对话框中*//************************************************************************/char variable[256];CWnd* pWnd = this->GetDlgItem(IDC_VIEW); //获取图片控件的窗口指针sprintf(variable,"SDL_WINDOWID=0x%1x",pWnd->GetSafeHwnd()); // 格式化字符串SDL_putenv(variable); //这句是最重要的了,将上面的字符串传入即可//剩下的就是设置视频播放大小的问题了,自己可以随便改SDL_Rect rect; //设置好播放的大小后传入SDL_SetVideoModeRECT rc;pWnd->GetWindowRect(&rc);rect.x = 0;rect.y = 0;rect.w = rc.right-rc.left;rect.h = rc.bottom-rc.top;// Register all formats and codecsavcodec_register_all();av_register_all();if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());exit(1);}以下N行代码都是解码的部分,就不写了,主要写和SDL嵌入有关的下面这句大家是相当的熟悉了,用过SDL播放的都应该知道// Make a screen to put our videoscreen = SDL_SetVideoMode(rect.w, rect.h, 0, 0); //此处需要设置成缩放大小if(!screen) {exit(1);}不知道大家看明白没?其实实现这个功能一共就需要四行代码,大家是不是有种蛋碎的感觉?char variable[256];CWnd* pWnd = this->GetDlgItem(IDC_VIEW); //获取图片控件的窗口指针sprintf(variable,"SDL_WINDOWID=0x%1x",pWnd->GetSafeHwnd()); // 格式化字符串SDL_putenv(variable); //这句是最重要的了,将上面的字符串传入即可只要把上面的SDL_WINDOWID传入后,不管你怎么画图,播放视频,都是在那个控件中显示!这个问题绝对不是我第一个想出来的,肯定有人已经知道,但是就这么一个简单的问题,百度上却没有一个人说明!可见中国的大环境啊!为了刚接触ffmpeg的TX少走弯路我会后续写自己对SDL在MFC中运作的一些体会。

海康视频监控平台多路回放控件使用说明书(IPlayBackCtrl)

海康视频监控平台多路回放控件使用说明书(IPlayBackCtrl)

多路回放控件使用说明书目录1.基本信息 (4)1.1组件描述 (4)1.2运行环境 (4)1.2.1硬件环境 (4)1.2.2软件环境 (4)1.3使用场景 (4)1.4技术制约及局限 (4)1.5参考资料 (5)2.接口定义 (5)2.1接口说明 (5)2.1.1基本业务 (5)2.1.1.1设置基本信息 (5)2.1.1.2设置窗口占用状态 (8)2.1.1.3设置窗口状态文字 (8)2.1.1.4设置录像查询结果 (9)2.1.1.5设置锁定/解锁结果 (10)2.1.1.6设置标签信息 (10)2.1.1.7设置标签操作结果 (11)2.1.1.8设置选中的窗口 (12)2.1.1.9获取选中的窗口 (12)2.1.1.10获取空闲窗口序号 (13)2.1.1.11获取窗口数量 (13)2.1.1.12设置合适的布局 (13)2.1.1.13设置布局属性值 (13)2.1.1.14设置是否保存布局属性值 (14)2.1.1.15设置Ip属性值 (14)2.1.1.16设置用户名属性值 (14)2.1.1.17设置权限码属性值 (14)2.1.1.18设置登录参数属性值 (15)2.1.1.19设置令牌 (15)2.1.1.20开始播放 (15)2.1.1.21停止播放 (16)2.1.1.22抓图 (16)2.1.1.23录像剪辑 (16)2.1.1.24设置基本信息(V6.4.1新增) (17)2.1.1.25控件自身登录平台接口(V6.4.1新增) (17)2.1.2参数设置 (18)2.1.2.1设置常用参数 (18)2.1.2.2设置性能参数 (20)2.1.2.3设置用户界面 (20)2.1.2.4屏蔽快捷键 (21)2.1.3工具接口 (21)2.1.3.1选择文件夹路径 (21)2.1.3.2获取系统盘符 (21)2.1.3.3获取用户目录 (22)2.1.3.4打开目录 (22)2.1.3.5打开文件 (22)2.1.3.6获取Base64编码 (23)2.2数据结构描述 (23)2.3接口调用说明 (24)2.3.1约束条件 (24)2.3.2内部查询录像 (24)2.3.3外部设置录像 (24)2.3.4控件事件 (25)2.3.5调用示例 (25)3.回放常见错误及错误码 (25)4.修订记录 (25)1.基本信息组件名称:MultiPlayBackOcx组件类型:开发库技术类别:Windows应用应用级别:部门级1.1组件描述功能描述:多路回放窗口,内部包含多窗口管理、录像查询、取流播放、播放控制、时间轴等。

基于SDL的Mpeg-4视频流实时解码与回放方法

基于SDL的Mpeg-4视频流实时解码与回放方法
关 键 词 S L Y V 解码 D U
A ETHoD M oF THE REAL. M E M PE . DEo TI G ‘ VI l DECoDI NG AND LAYI P NG AS B ED oN DL S
Z u Jn y Ya gS ua g Xu h h ig u n h tn eZ i
制来实现实时,D S L调用视 频解码器 来实现解码工作 , 利用 S L本 身对 Y V格 式的视 频数据 处理 来实 现 回放 。在 1 H D U G z处 理器 的 P c上的测试表 明, 可获得 2 0帧/ 的解码播放效果 , 秒 并且 画面流畅, 而且程序具 有 良好的跨平 台性 。
基 于 S L的 Mp g4视 频 流 实 时解 码 与 回放 方 法 D e-
朱靖宇 杨树堂 薛 质
( 上海交通大学信息安全工程学院 上海 20 3 ) 000


主要研 究一个基 于跨 平台 多媒体软件开发 库——s L的视 频流实 时解码 与 回放实现 方 法。主 要利用 S L对 线程的控 D D
・Drc D: i t 它为主流的 桌上 型计算 机和 ltre 用 户提 供 e3 nent
实时的 、 互 的 3 技术 。 交 D
・ Drclpt它简化你 的应 用程序访 问 鼠标 、 i t u: e n 键盘 和操 纵 杆设备 的能力 。 ・ Drc e p 一套简单 的 A I向你提供 安装 D r t i tt : eS u P i eX部件 e
维普资讯
第 2 第 6期 3卷 20 0 6年 6月 ຫໍສະໝຸດ 计 算机 应 用与软 件
Co u e mp tr App iai n n o wa e l t s a d S f r c o t

SDL+FFmpeg实现视频简单播放

SDL+FFmpeg实现视频简单播放

实现视频的基本播放1.新建工程,右击——属性:a)C/C++——常规——附加包含目录:引入ffmpeg和SDL的include目录b)C/C++——所有选项——附加包含目录:引入ffmpeg和SDL的include目录c)链接器——常规——附加库目录:引入ffmpeg和SDL的lib目录d)链接器——输入——附加依赖项:avcodec.lib;avformat.lib;avutil.lib;avdevice.lib;avfilter.lib;postproc.lib;swresample.lib;swscale.lib;SDL.lib;2.新建头文件:stdafx.h包含一些常用的但不经常更改的头文件#pragma once#include<stdio.h>#include<tchar.h>#include<io.h>#include<direct.h>#include<SDKDDKVer.h>extern"C"{#include"libavcodec\avcodec.h"#include"libavformat\avformat.h"#include"libswscale\swscale.h"//新版里的图像转换结构需要引入的头文件#include"SDL.h"#include"SDL_thread.h"};3.新建源文件:main.cppA)包含头文件:#include"stdafx.h"B)创建主程序:int_tmain(int argc, _TCHAR* argv[]) {char filepath[]="D:\\TDDOWNLOAD\\123\\123.mkv";//文件路径//1.初始化av_register_all();//2.打开视频文件AVFormatContext *pFormatCtx;pFormatCtx =avformat_alloc_context();//分配一个AVFormatContext结构,负责申请一个AVFormatContext结构的内存,并进行简单初始化,从中得到我们想要的信息if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){return -1;}//3.获取视频信息if(avformat_find_stream_info(pFormatCtx,NULL)<0){return -1;}//av_dump_format();dump只是个调试函数,输出文件的音、视频流的基本信息,帧率、分辨率、音频采样等等av_dump_format(pFormatCtx, 0, filepath, false);//输出文件信息//4.查找第一个视频流,记录该流的编码序号int i,videoStream=-1;for(i=0;i<pFormatCtx->nb_streams;i++){if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){videoStream=i;break;}}if(videoStream==-1){return -1;}//5.得到视频流上下文编码的指针AVCodecContext *pCodecCtx;pCodecCtx=pFormatCtx->streams[videoStream]->codec;//6.寻找视频流的解码器AVCodec *pCodec;pCodec=avcodec_find_decoder(pCodecCtx->codec_id);if(pCodec==NULL){return -1;}//7.打开解码器if(avcodec_open2(pCodecCtx,pCodec,NULL)<0){return -1;}//8.为解码帧分配内存AVFrame *pFrame,*pFrameYUV;pFrame=av_frame_alloc();pFrameYUV=av_frame_alloc();//9.根据像素格式和分辨率获得图片所需空间大小uint8_t *out_buffer;out_buffer=newuint8_t[avpicture_get_size(PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height)];//为已经分配的空间的结构体AVPicture挂上一段用于保存数据的空间avpicture_fill((AVPicture*)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);/*****************事件处理************************/bool quit=false;//确保程序一直等待quit,用它来跟踪用户是否想要退出程序SDL_Event event;//将要用到的事件结构体//10.启动SDLif(SDL_Init(SDL_INIT_EVERYTHING)){return -1;}//11.建立一个指定高度和宽度的窗口SDL_Surface *screen;screen=SDL_SetVideoMode(pCodecCtx->width,pCodecCtx->height,0,0);if(!screen){return -1;}//12.在屏幕上创建一个YUV覆盖,以便于我们输入视频上去SDL_Overlay *bmp;bmp=SDL_CreateYUVOverlay(pCodecCtx->width,pCodecCtx->height,SDL_YV12_OVERLAY,screen);//13.定义数据包int y_size=pCodecCtx->width *pCodecCtx->height;AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));av_new_packet(packet,y_size);//创建指定大小的数据包用来作为缓冲区//14.根据编码信息设置渲染格式struct SwsContext *img_convert_ctx;img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);//15.不停地从码流中提取出帧数据,存放到数据包中,并且判断用户是否要退出!int ret,got_picture;while(av_read_frame(pFormatCtx,packet)>=0 && quit==false){//16.判断帧的类型,对于视频帧进行解码if(packet->stream_index==videoStream){ret=avcodec_decode_video2(pCodecCtx,pFrame,&got_picture,packet);if(ret<0){return -1;//解码失败}if(got_picture){//解码成功,获得图片,并输出到SDL窗口sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);SDL_LockYUVOverlay(bmp);bmp->pixels[0]=pFrameYUV->data[0];bmp->pixels[2]=pFrameYUV->data[1];bmp->pixels[1]=pFrameYUV->data[2];bmp->pitches[0]=pFrameYUV->linesize[0];bmp->pitches[2]=pFrameYUV->linesize[1];bmp->pitches[1]=pFrameYUV->linesize[2];SDL_UnlockYUVOverlay(bmp);SDL_Rect rect;//用于确定SDL_Overlay显示的位置。

FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放

FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放

FFmpeg开发笔记(九):ffmpeg解码rtsp流并使⽤SDL同步播放前⾔ ffmpeg播放rtsp⽹络流和摄像头流。

Demo 使⽤ffmpeg播放局域⽹rtsp1080p海康摄像头:延迟0.2s,存在马赛克 使⽤ffmpeg播放⽹络rtsp⽂件流:偶尔卡顿,延迟看不出 使⽤vlc软件播放局域⽹rtsp1080p海康摄像头:演⽰2s,不存在马赛克 使⽤vlc软件播放⽹络rtsp⽂件流:不卡顿,延迟看不出FFmpeg基本播放流程ffmpeg解码流程 ffmpeg新增API的解码执⾏流程。

新api解码基本流程如下:步骤⼀:注册: 使⽤ffmpeg对应的库,都需要进⾏注册,可以注册⼦项也可以注册全部。

步骤⼆:打开⽂件: 打开⽂件,根据⽂件名信息获取对应的ffmpeg全局上下⽂。

步骤三:探测流信息: ⼀定要探测流信息,拿到流编码的编码格式,不探测流信息则其流编码器拿到的编码类型可能为空,后续进⾏数据转换的时候就⽆法知晓原始格式,导致错误。

步骤四:查找对应的解码器 依据流的格式查找解码器,软解码还是硬解码是在此处决定的,但是特别注意是否⽀持硬件,需要⾃⼰查找本地的硬件解码器对应的标识,并查询其是否⽀持。

普遍操作是,枚举⽀持⽂件后缀解码的所有解码器进⾏查找,查找到了就是可以硬解了(此处,不做过多的讨论,对应硬解码后续会有⽂章进⾏进⼀步研究)。

(注意:解码时查找解码器,编码时查找编码器,两者函数不同,不要弄错了,否则后续能打开但是数据是错的)步骤五:打开解码器 开打解码器的时候,播放的是rtsp流,需要设置⼀些参数,在ffmpeg中参数的设置是通过AVDictionary来设置的。

使⽤以上设置的参数,传⼊并打开获取到的解码器。

AVDictionary *pAVDictionary = 0// 设置缓存⼤⼩ 1024000byteav_dict_set(&pAVDictionary, "buffer_size", "1024000", 0);// 设置超时时间 20sav_dict_set(&pAVDictionary, "stimeout", "20000000", 0);// 设置最⼤延时 3sav_dict_set(&pAVDictionary, "max_delay", "30000000", 0);// 设置打开⽅式 tcp/udpav_dict_set(&pAVDictionary, "rtsp_transport", "tcp", 0);ret = avcodec_open2(pAVCodecContext, pAVCodec, &pAVDictionary);if(ret){LOG << "Failed to avcodec_open2(pAVCodecContext, pAVCodec, pAVDictionary)";return;}步骤六:申请缩放数据格式转换结构体 此处特别注意,基本上解码的数据都是yuv系列格式,但是我们显⽰的数据是rgb等相关颜⾊空间的数据,所以此处转换结构体就是进⾏转换前到转换后的描述,给后续转换函数提供转码依据,是很关键并且⾮常常⽤的结构体。

C语言基于GTK+Libvlc实现的简易视频播放器 (一)

这差不多已经 10 年过去了。今天,在 GTK+ 的最新稳定版本 —— 2.8 版上 (3.0 测试中),仍然在进行许多活动,同时,GIMP 无疑仍然是使用 GTK+ 的 最著名的程序之一,不过它已经不是惟一的使用 GTK+ 的程序了。已经为 GTK+ 编写了成百上千的应用程序,而且至少有两个主要的桌面环境(Xfce 和 GNOME)用 GTK+ 为用户提供完整的工作环境。
playpause_button =
gtk_button_new_from_icon_name("media-playback-start",
GTK_ICON_SIZE_BUTTON);
stop_button = gtk_button_new_from_icon_name("media-playback-stop",
GTK+虽然是用 C 语言写的,但是您可以使用你熟悉的语言来使用 GTK+,因为 GTK+已经被绑定到几乎所有流行的语言上,如:C++,PHP, Guile,Perl, Python, TOM, Ada95, Objective C, Free Pascal, and Eiffel
使用 GTK+的优秀应用程序:
filemenu = gtk_menu_new(); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), filemenu_openitem);
// 将 filemenu 设置为上一级 fileitem 的子菜单,然后将 fileitem 添加进 menubar,最后将 menubar 放置进 vbox
//创建一个方向垂直间距为 0 的 box 容器,并添加到前面创建的 window 中 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

设备网络SDK编程指南(远程回放)

5.1.1 初始化 SDK NET_DVR_Init ..............................................................................24 5.1.2 释放 SDK 资源 NET_DVR_Cleanup .................................................................24 5.2 获取错误信息...........................................................................................................24 5.2.1 返回最后操作的错误码 NET_DVR_GetLastError ..........................................24 5.3 用户注册...................................................................................................................25 5.3.1 用户注册设备 NET_DVR_Login_V30..............................................................25 5.3.2 用户注销 NET_DVR_Logout ...........................................................................25 5.4 录像文件回放、下载及锁定...................................................................................26 录像文件的查找 ............................................................................................................. 26 5.4.1 根据文件类型、时间查找设备录像文件 NET_DVR_FindFile_V30.............26 5.4.2 逐个获取查找到的文件信息 NET_DVR_FindNextFile_V30 ..........................26 5.4.3 关闭文件查找,释放资源 NET_DVR_FindClose_V30..................................27 回放录像文件 ................................................................................................................. 27 5.4.4 按文件名回放录像文件 NET_DVR_PlayBackByName ..................................27 5.4.5 按时间回放录像文件 NET_DVR_PlayBackByTime .......................................28 5.4.6 控制录像回放的状态 NET_DVR_PlayBackControl_V40 ...............................28 5.4.7 停止回放录像文件 NET_DVR_StopPlayBack ................................................30 回放录像文件时的数据捕获 ......................................................................................... 31 5.4.8 捕获回放的录像数据,并保存成文件 NET_DVR_PlayBackSaveData.........31 5.4.9 停止保存录像数据 NET_DVR_StopPlayBackSave..........................................31 5.4.10 注册回调函数,捕获录像数据 NET_DVR_SetPlayDataCallBack ..................31 回放的其他操作 ............................................................................................................. 32 5.4.11 获取录像回放时显示的 OSD 时间 NET_DVR_GetPlayBackOsdTime ..........32 5.4.12 录像回放时抓图,并保存在文件中 NET_DVR_PlayBackCaptureFile .........32 5.4.13 刷新显示回放窗口 NET_DVR_RefreshPlay...................................................33 下载录像文件 ................................................................................................................. 33 5.4.14 按文件名下载录像文件 NET_DVR_GetFileByName ....................................33 5.4.15 按时间下载录像文件 NET_DVR_GetFileByTime..........................................33

实时记录及实时回放软件的设计与实现

图1 实时记录功能图2 实时显示及实时回放同步进行由于飞行试验实时监控自身所具有的特点,本软件的实现具体有以下几个特点。

(1)实时监控与实时回放通过多线程实现并行执行,两者之间互不影响,安全监控与实时数据分析同时进行,增加了实时数据处理的灵活性,减少了试飞工程师的工作量。

(2)可根据试飞工程师及试飞任务需求,任意时刻开启和结束存盘,任意时刻开启和停止回放,两者之间互不干扰、相互独立[4]。

(3)可根据试飞工程师及任务需求,设置不同的回放速度,实现数据的快进和慢放,便于试飞工程师查找关键时刻的关键参数。

(4)数据文件采用ASCII格式存储,便于试飞工程师进行数据读取和曲线绘制。

(5)软件具有一定的可移植性,扩展了其应用范围。

编写实时记录和实时回放软件时,将关键实现过程封装成子VI程序,比如,打开数据文件.vi、数据存储.vi等。

对于其他飞机的实时监控软件,只要引用相应的子VI程序,再对相应参数进行修改便可完成相应的监控软件的设计。

4 结 语实时监控是飞行试验的重要环节,它有力保障了飞行试验的安全和质量。

随着型号试飞工作的不断展开,面对试飞工程师提出的实时监控与实时数据处理分析的新需求,项目组人员研究和开发了该软件,它不但可以在不影响实时监控、确保飞行安全的情况下对飞行数据进行重新处理分析,而且(下转第79页)图6 土壤湿度YL_69实物图3 软件设计该系统软件采用C语言编写,编译环境为Keil C51语言与汇编语言相比,C语言编程的可读性高,便于理解和交流,在学习上,C语言也比较容易上手[5]。

Keil C51的目标代码效率非常高。

4 结 语本文设计了一个智能浇花系统,该系统的智能部分:在单片机内设定一个土壤湿度的预设值,这个预设值可以通过按键进行加、减。

当检测到土壤的湿度低于预设定的湿度时,76页)保证了实时监控、分析、判断、决策的时效性。

该软件。

vue+flv.js+SpringBoot+websocket实现视频监控与回放功能

vue+flv.js+SpringBoot+websocket实现视频监控与回放功能⽬录需求:思路:准备⼯作:实现:最后:需求:vue+springboot的项⽬,需要在页⾯展⽰出海康的硬盘录像机连接的摄像头的实时监控画⾯以及回放功能.之前项⽬⾥是纯前端实现视频监控和回放功能.但是有局限性.就是ip地址必须固定.新的需求⾥设备ip不固定.所以必须换⼀种思路.通过设备的主动注册,让设备去主动连接服务器后端通过socket推流给前端实现实时监控和回放功能;思路:1:初始化设备.后端项⽬启动时就调⽤初始化⽅法.2:开启socket连接.前端页⾯加载时尝试连接socket.3:点击播放,调⽤后端推流接⼝.并且前端使⽤flv.js实现播放.准备⼯作:1:vue项⽬引⼊flv.js。

npm install --save flv.jsmain.js⾥⾯引⼊import flvjs from ‘flv.js’;e(flvjs)但是这⾥我遇见⼀个坑.开发模式没有问题.但是打包之后发现ie浏览器报语法错误.不⽀持此引⽤.所以修改引⽤地址.在webpack.base.conf.js的module.exports下添加resolve: {extensions: ['.js', '.vue', '.json'],alias: {'vue$': 'vue/dist/vue.esm.js','@': resolve('src'),'flvjs':'flv.js/dist/flv.js'}},plugins下添加plugins: [new webpack.ProvidePlugin({flvjs:'flvjs',$: "jquery",jQuery: "jquery","window.jQuery": "jquery"})],最后页⾯引⼊时:import flvjs from "flv.js/dist/flv.js";2.准备⼀个硬盘录像机,并添加⼀个摄像头设备以做测试使⽤.硬盘录像机设置为主动注册模式.并配置好ip和端⼝以及⼦设备ID在设置⾥的⽹络设置⾥⾯3.后端搭建好websocket⼯具类包含通⽤的OnOpen,onClose,onError等⽅法.实现:1.项⽬启动开启设备服务.这个SDKLIB⾥⾯都有就不介绍了.2.页⾯加载尝试开启socket连接.//尝试连接websocketstartSocket(channelnum, device_value) {try {let videoWin = document.getElementById(this.currentSelect);if (flvjs.isSupported()) {let websocketName ="/device/monitor/videoConnection/" + channelnum + device_value;console.log("进⼊连接websocket", this.ipurl + websocketName);const flvPlayer = flvjs.createPlayer({type: "flv",//是否是实时流isLive: true,//是否有⾳频hasAudio: false,url: this.ipurl + websocketName,enableStashBuffer: true,},{enableStashBuffer: false,stashInitialSize: 128,});flvPlayer.on("error", (err) => {console.log("err", err);});flvjs.getFeatureList();flvPlayer.attachMediaElement(videoWin);flvPlayer.load();flvPlayer.play();return true;}} catch (error) {console.log("连接websocket异常", error);return false;}},这⾥传的参数是通道号和设备信息.⽆需在意.只要是唯⼀key就可以.2.socket连接成功后.调⽤后端推流⽅法实现播放.这⾥说⼀下后端的推流⽅法.调⽤SDK⾥的CLIENT_RealPlayByDataType⽅法/*** 实时预览拉流** @param loginHandler 登录句柄* @param channel 通道号* @param emDataType 回调拉出的码流类型,{@link NetSDKLib.EM_REAL_DATA_TYPE}*/public long preview(long loginHandler, int channel, NetSDKLib.fRealDataCallBackEx realDataCallBackEx, fRealDataCallBackEx2 realPlayDataCallback, int emDataType, int rType, boolean saveFile, int emAudioType) { _IN_REALPLAY_BY_DATA_TYPE inParam = new _IN_REALPLAY_BY_DATA_TYPE();_OUT_REALPLAY_BY_DATA_TYPE outParam = new _OUT_REALPLAY_BY_DATA_TYPE();inParam.nChannelID = channel;inParam.rType = rType;if(realDataCallBackEx!=null){inParam.cbRealData=realDataCallBackEx;}if(realPlayDataCallback!=null){inParam.cbRealDataEx = realPlayDataCallback;}inParam.emDataType = emDataType;inParam.emAudioType=emAudioType;if (saveFile) {inParam.szSaveFileName = UUID.randomUUID().toString().replace(".", "").replace("-", "") + "." + EMRealDataType.getRealDataType(emDataType).getFileType(); }NetSDKLib.LLong realPlayHandler = netsdk.CLIENT_RealPlayByDataType(new NetSDKLib.LLong(loginHandler), inParam, outParam, 3000);if (realPlayHandler.longValue() != 0) {netsdk.CLIENT_MakeKeyFrame(new NetSDKLib.LLong(loginHandler),channel,0);RealPlayInfo info = new RealPlayInfo(loginHandler, emDataType, channel, rType);realPlayHandlers.put(realPlayHandler.longValue(), info);} else {log.error("realplay failed.error is " + ENUMERROR.getErrorMessage(), this);}return realPlayHandler.longValue();}注意:这⾥的码流类型选择flv.回调函数⾥⾯:// 回调建议写成单例模式, 回调⾥处理数据,需要另开线程@Autowiredprivate WebSocketServer server;private Log log = Log.get(WebSocketRealDataCallback.class);@Overridepublic void invoke(NetSDKLib.LLong lRealHandle, int dwDataType, Pointer pBuffer, int dwBufSize, int param, Pointer dwUser) {RealPlayInfo info = DeviceApi.realPlayHandlers.get(lRealHandle.longValue());if (info != null && info.getLoginHandler() != 0) {//过滤码流byte[] buffer = pBuffer.getByteArray(0, dwBufSize);if (info.getEmDataType() == 0 || info.getEmDataType() == 3) {//选择私有码流或mp4码流,拉流出的码流都是私有码流if (dwDataType == 0) {(dwDataType + ",length:" + buffer.length + " " + Arrays.toString(buffer), WebSocketRealDataCallback.class);sendBuffer(buffer, lRealHandle.longValue());}} else if ((dwDataType - 1000) == info.getEmDataType()) {(dwDataType + ",length: " + buffer.length + Arrays.toString(buffer), WebSocketRealDataCallback.class);sendBuffer(pBuffer.getByteArray(0, dwBufSize), lRealHandle.longValue());}}}以及调⽤Websocket⾥⾯的sendMessageToOne发送给指定客户端/*** 发送数据* @param bytes* @param realPlayHandler*/private static void sendBuffer(byte[] bytes, long realPlayHandler) {/*** 发送流数据* 使⽤pBuffer.getByteBuffer(0,dwBufSize)得到的是⼀个指向native pointer的ByteBuffer对象,其数据存储在native,* ⽽webSocket发送的数据需要存储在ByteBuffer的成员变量hb,使⽤pBuffer的getByteBuffer得到的ByteBuffer其hb为null* 所以,需要先得到pBuffer的字节数组,⼿动创建⼀个ByteBuffer*/ByteBuffer buffer = ByteBuffer.wrap(bytes);server.sendMessageToOne(realPlayHandler, buffer);}这⾥传的参数是设备初始化的时候得到的登录句柄.以及流数据./*** 发送binary消息给指定客户端** @param realPlayHandler 预览句柄* @param buffer 码流数据*/public void sendMessageToOne(long realPlayHandler, ByteBuffer buffer) {//登录句柄⽆效if (realPlayHandler == 0) {log.error("loginHandler is invalid.please check.", this);return;}RealPlayInfo realPlayInfo = AutoRegisterEventModule.findRealPlayInfo(realPlayHandler);if(realPlayInfo == null){//连接已断开}String key = realPlayInfo.getChannel()+realPlayInfo.getSbbh();Session session = sessions.get(key);if (session != null) {synchronized (session) {try {session.getBasicRemote().sendBinary(buffer);byte[] bytes=new byte[buffer.limit()];buffer.get(bytes);} catch (IOException e) {e.printStackTrace();}}} else {//log.error("session is null.please check.", this);}}这样就实现了视频监控.效果:分享⼀下websocket代码:package sdk.webpreview.websocket;import cn.hutool.log.Log;import cn.hutool.log.LogFactory;import ponent;import javax.websocket.*;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.atomic.AtomicInteger;/*** @description websocket实现类*/@ServerEndpoint("/websocket/{realPlayHandler}")@Componentpublic class WebSocketServer {private static Log log = LogFactory.get(WebSocketServer.class);private FileOutputStream outputStream;/*** 静态变量,⽤来记录当前在线连接数。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

浙江理工大学学报,第26卷,第6期,2009年11月Journal of Zhejiang Sci2Tech U niversityVol.26,No.6,Nov.2009文章编号:167323851(2009)0620897204应用SDL及GTK+实现视频多路回放江达秀,许建龙,孙树森(浙江理工大学信息电子学院,杭州310018) 摘 要:结合了SDL多媒体开发库、GT K+2.0图形开发包以及多线程编程技术的应用,在Linux平台下实现了一种能同时回放多个视频文件的软件。

利用该软件视频监控系统可以同时查看多个视频文件,并且由于GT K+2.0图形开发包和SDL多媒体开发库的跨平台性,该软件的可移植性强。

关键词:SDL;GT K+2.0;多路回放;视频回放;视频监控系统中图分类号:TP391.41 文献标识码:A0 引 言SDL(Simple Direct Media Layer)是一个完整的游戏、多媒体开发包,它能支持大部分操作系统平台,如: Linux、Windows、B EOS、MacOSX、FreeBSD、QNX、ChromeOS等。

SDL能为跨平台开发提供一个统一的编程接口,为应用程序开发特别是代码移植提供便利。

SDL在多种操作系统上提供一个统一的存取底层音频、视频、键盘、鼠标、游戏杆、CDROM等设备的方法,使用它们可以很方便地编写跨平台的游戏、音频应用、视频应用等,使用者不必知道这些操作系统的具体差别,只需要调用SDL提供的A PI函数就可以容易地实现音视频的操作[1]。

相比较于Linux下其他的图形库如SV GAL IB和FBCON,使用SDL来开发多路视频回放软件,不必直接对底层硬件操作,可以省去许多繁琐的开发步骤。

GT K+(GIM P Toolkit,GIM P)是Linux下的图形开发库,它是为了GNU图像操作程序(简称GIM P)而开发的,现在已经成为GNU桌面环境项目的一个组成部分(Gnome)。

实际上,GT K+是包括一组C语言库:GT K,GD K和Glib,是一个跨平台的、由事件驱动的工具集[2]。

1 关键技术1.1 SDL_HAC K机制本文使用SDL_HAC K机制把SDL和GT K+2.0相结合创建播放窗口。

1.1.1 相关说明[324]a)SDL_SetVideoMode:SDL库用来创建指定宽度、高度以及深度显示模式的窗口,创建其函数原型为SDL_Surface3SDL_SetVideoMode(int widt h,int height,int bpp,Uint32flags)。

b)SDL_WINDOWID:系统环境变量,在本文中其值有函数gt k_drawing_area_new的返回值赋值。

c)gt k_drawing_area_new:GT K+2.0的函数,用来创建绘图构件,其函数原型为Gt kWidget3gt k_ drawing_area_new(void)。

d)SDL_Init:初始化SDL子系统函数,其原型为int SDL_Init(Uint32flags)。

SDL库包含音频、视频、收稿日期:2009-02-25作者简介:江达秀(1982- ),男,浙江温州人,硕士研究生,主要从事图像处理、数字视频方面的研究。

898 浙 江 理 工 大 学 学 报2009年 第26卷键盘、鼠标、游戏杆、CDROM等子系统,使用任何子系统前都必须调用该函数来初始化。

e)SDL_Create YUVOverlay:SDL库用来创建YUV画面的,其函数原型为SDL_Overlay3SDL_Cre2 ate YUVOverlay(int widt h,int height,Uint32format,SDL_Surface3display)。

1.1.2 SDL_HAC K机制描述SDL_HAC K机制如下[5]:当通过SDL_SetVideoMode创建一个SDL_Surface时,系统会先查询环境变量SDL_WINDOWID,当其值不存在时,就把创建的SDL_Surface默认为播放窗口;而当SDL_WINDOWID 的值存在时,则会把创建的SDL_Surface嵌入到该环境变量指定的值中,SDL_Surface仅表示视频显示的宽度、高度以及深度,而SDL_WINDOWID的值才是播放窗口。

创建播放窗口的主要实现代码如下:{ gchar SDL_window ID[32]; sp rintf(SDL_window ID,″SDL_WINDOWID=%ld″,GD K_WINDO XWINDOW(w_drawing_area->window)); p utenv(SDL_windowhack); SDL_Surface3SDL_surface; SDL_surface=SDL_SetVideoMode(p Widt h,p Height,0,SDL_HWSU RFACE);}1.1.3 使用SDL_HAC K需要注意的问题[5]a)SDL_HAC K过程必须在调用SDL_Init之前。

b)SDL_HAC K必须在环境变量SDL_WINDOWID指定的构件都实例化后才能调用。

c)对于每一个应用程序,SDL_HAC K只允许拥有一个SDL_Surface。

1.2 YUV画面YUV画面是SDL库用来显示YUV格式的视频文件的,它是SDL_Surface的一个矩形区域,代表了SDL_Surface一块线性内存区域;它在SDL库中的数据结构为SDL_Overlay,通常都驻留在显示内存中,同一个SDL_Surface的各个YUV画面是独立的。

使用YUV画面的优点是:目前的绝大部分显卡都支持YUV画面,YUV画面支持硬件的缩放;使用种方式来显示视频的缺点是:具有独占性,在一块显卡上同时只有一个YUV画面处于活动状态,因此同时只能有一路播放线程使用YUV画面。

在采用YUV画面显示视频时,画面显示的速度和质量与计算机硬件有较大的关系。

在多路视频同时播放时,画面可能会出现闪烁,解决的方法是在创建SDL_Suface前,加入p utenv(“SDL_V IDEO_YUV_ HWACCEL=0”),把硬件加速取消。

1.3 多线程编程在视频监控系统中,回放功能需要同时播放任意多个视频文件,若只有一个线程(线程是操作系统分配CPU时间的基本单位,一个线程可以执行应用程序的任何部分,一个应用程序至少包含一个主线程)来播放,很难实现任意多个文件的同时播放。

如果设计成多个线程,就可以有效利用CPU资源,有利于同时播放多个视频文件。

在使用多线程时需要考虑线程互斥和线程同步问题,线程互斥是指对于共享的操作系统资源,在各线程访问时的排它性。

当有若干个线程都要使用某一共享资源时,任何时刻只允许一个线程去访问,其它要使用该资源的线程必须等待,直到占用该资源者释放了该资源。

线程同步是指若干个线程之间具有一种制约关系,一个线程执行依赖于另一个线程的消息,当一个线程没有等到另一个线程的消息时,应该等待,直到消息到达时,才被唤醒[6]。

进行程序设计时,本文使用G L IB线程系统(gt hread),在线程初始化时,首先是调用函数g_t hread_sup2 ported来判断线程是否初始化,如果其返回FAL SE则表明线程并未初始化,这时必须调用g_t hread_init来初始化;创建播放线程调用函数g_t hread_creat()。

2 多路回放的设计与实现图1 多路回放流程图2.1 多路回放设计多路回放是整个设计的关键部分,其核心思想是使用SDL_HAC K机制创建主播放窗口,打开视频文件创建播放线程(调用解码器获得数据,送到后台缓冲区),同时调用函数SDL _Create YUVOverlay 在播放窗口上创建YUV 画面(每打开一个视频文件就调用该函数,一个YUV 画面代表一路播放通道,它在播放窗口的位置、高度以及宽度由视频图像尺寸决定,视频数据由相对应的缓冲区获得)并显示视频。

多路回放流程图如图1所示。

2.2 多路回放的实现多路回放主要实现过程如下:a )调用函数SDL_Iinit (SDL_IN IT_V IDEO )初始化SDL 视频子系统,并注册退出函数atexit (SDL_Quit );b )创建SDL_Surface 以及主窗口,初始化通道链表,通道链表的每个元素是一个结构体,用来保存线程号、通道号、打开的视频文件以及缓冲区指针;c )调用g_t hread_create ((GThreadFunc )SetDecCallBack ,user_data ,FAL SE ,NULL ),创建播放线程,其中输入参数SetDecCallBack 是一个指针函数,它的作用是调用解码器获得视频数据送到缓冲区并设置播放回调函数DecCallback (int nPort ,char 3pBuf ,int nSize ,FRAM E_IN FO 3p FrameInfo ),DecCallback ()函数的作用是设置播放函数;DecCallback 函数的参数说明:nPort , 播放通道号(即YUV 画面);nBuf ,解码后的视频数据;nSize ,解码后的视频数据pBuf 的长度;p FrameInfo ,结构体,保存每帧图像信息。

d )创建YUV 画面,显示视频数据,要把视频显示在YUV 画面必须把数据从缓冲区写入到SDL_Over2图2 程序运行效果图lay 结构体中,在写入前需要先调研SDL_Lock YUVOverlay 函数锁定该结构体(这样是为了防止在将数据写入时有程序的其他部分访问操作该部份内存);然后调用SDL_Display YUVOverlay 函数,把SDL_Overlay 结构中YUV 视频数据显示在屏幕上;最后用SDL_Unlock YUVOverlay 函数解除对SDL_Overlay 的锁定;e )每次打开一个新的视频文件就从步骤c )开始,创建播放线程,调用解码器获得数据并输送到缓冲区,设置播放回调函数DecCallback ,在该函数中创建YUV 画面显示视频。

2.3 多路回放实现后的效果本文利用上述关键技术和设计方案,实现后的程序运行效果如图2。

3 结束语在分析视频播放技术和视频的存储结构的基础上,通过对SDL 多媒体开发库和GT K +2.0以及多线程技术的研究,在Linux 下实现了一种能同时回放多个视频文件的软件,并达到了很好的效果。

998第6期江达秀等:应用SDL 及GT K +实现视频多路回放009 浙 江 理 工 大 学 学 报2009年 第26卷参考文献:[1]蒋 鹏.基于SDL库的跨平台多媒体应用[J].福建电脑,2003,31(5):39-40.[2]Logan S.Gtk+程序设计[M].北京:清华大学出版社,2002.[3]GT K+2.0ReferenceManua[EB/OL]./doc.[4]Martin Donlon.SDL Library Documentation[EB/OL]..2001.[5]Pazera E.Focus on SDL[M].北京:人民邮电出版社,2000:31-86.[6]黎芬芳,余致春,杨煜普.基于多线程编程的视频监控系统四路回放的设计[J].上海交通大学学报,2005,26(4):223-227.Implementation of Video Multi2Channel Playback System withthe Using of Sdl and G tk+2.0J IA N G Da2x i u,X U J iang2long,S U N S hu2sen(School of Information and Elect ro nics,Zhejiang Sci2Tech University,Hangzho u310018,China)Abstract:This paper int roduces t he implementation of t he multi2channel video playback system in t he Linux platform wit h t he using of SDL and GT K+2.0,it can review several video2files at t he same time wit h t he system.Key words:SDL;GT K+2.0;multi2channel;video playback;video surveillance(责任编辑:陈和榜)。

相关文档
最新文档