EasyPlayer是一个RTSP专属的视频流媒体播放器,在GitHub上开源大部分源码。其主要功能有播放抓图录制视频实时静音/取消静音

EasyPlayer-RTSP-Win抓图代码重构

EasyPlayer-RTSP-Win(下文简称:EasyPlayer)播放器之前抓图代码主要通过OpenCV来实现,且数据格式转换的效率过于低下;故而在当时的代码中采用线程机制来解决抓图导致视频播放时卡顿的问题;

而最新版的EasyPlayer为了精简代码也为了提高抓图效率,采用ffmpeg进行抓图,为了保证视频播放的流畅性,线程机制仍然保留。

采用ffmpeg进行抓图代码如下:

// 抓图函数实现
int take_snapshot(char *file, int w, int h, uint8_t *buffer, AVPixelFormat Format)
{char              *fileext = NULL;enum AVCodecID     codecid = AV_CODEC_ID_NONE;struct SwsContext *sws_ctx = NULL;AVPixelFormat      swsofmt = AV_PIX_FMT_NONE;AVFrame            picture = {};int                ret     = -1;AVFormatContext   *fmt_ctxt   = NULL;AVOutputFormat    *out_fmt    = NULL;AVStream          *stream     = NULL;AVCodecContext    *codec_ctxt = NULL;AVCodec           *codec      = NULL;AVPacket           packet     = {};int                retry      = 8;int                got        = 0;// init ffmpegav_register_all();fileext = file + strlen(file) - 3;if (_stricmp(fileext, "png") == 0) {codecid = AV_CODEC_ID_APNG;swsofmt = AV_PIX_FMT_RGB24;}else {codecid = AV_CODEC_ID_MJPEG;swsofmt = AV_PIX_FMT_YUVJ420P;}AVFrame video;int numBytesIn;numBytesIn = av_image_get_buffer_size(Format, w, h, 1);av_image_fill_arrays(video.data, video.linesize, buffer, Format, w, h, 1);video.width = w;video.height = h;video.format = Format;// alloc picturepicture.format = swsofmt;picture.width  = w > 0 ? w : video.width;picture.height = h > 0 ? h : video.height;int numBytes = av_image_get_buffer_size(swsofmt, picture.width, picture.height , 1);buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));av_image_fill_arrays(picture.data, picture.linesize, buffer, swsofmt, picture.width, picture.height, 1);// scale picturesws_ctx = sws_getContext(video.width, video.height, (AVPixelFormat)Format/*video->format*/,picture.width, picture.height, swsofmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);if (!sws_ctx) {//av_log(NULL, AV_LOG_ERROR, "could not initialize the conversion context jpg\n");goto done;}sws_scale(sws_ctx, video.data, video.linesize, 0, video.height, picture.data, picture.linesize);// do encodingfmt_ctxt = avformat_alloc_context();out_fmt  = av_guess_format(codecid == AV_CODEC_ID_APNG ? "apng" : "mjpeg", NULL, NULL);fmt_ctxt->oformat = out_fmt;if (!out_fmt) {//av_log(NULL, AV_LOG_ERROR, "failed to guess format !\n");goto done;}if (avio_open(&fmt_ctxt->pb, file, AVIO_FLAG_READ_WRITE) < 0) {//av_log(NULL, AV_LOG_ERROR, "failed to open output file: %s !\n", file);goto done;}stream = avformat_new_stream(fmt_ctxt, 0);if (!stream) {//av_log(NULL, AV_LOG_ERROR, "failed to create a new stream !\n");goto done;}codec_ctxt                = stream->codec;codec_ctxt->codec_id      = out_fmt->video_codec;codec_ctxt->codec_type    = AVMEDIA_TYPE_VIDEO;codec_ctxt->pix_fmt       = swsofmt;codec_ctxt->width         = picture.width;codec_ctxt->height        = picture.height;codec_ctxt->time_base.num = 1;codec_ctxt->time_base.den = 25;codec = avcodec_find_encoder(codec_ctxt->codec_id);if (!codec) {//av_log(NULL, AV_LOG_ERROR, "failed to find encoder !\n");goto done;}if (avcodec_open2(codec_ctxt, codec, NULL) < 0) {//av_log(NULL, AV_LOG_ERROR, "failed to open encoder !\n");goto done;}while (retry-- && !got) {if (avcodec_encode_video2(codec_ctxt, &packet, &picture, &got) < 0) {//av_log(NULL, AV_LOG_ERROR, "failed to do picture encoding !\n");goto done;}if (got) {ret = avformat_write_header(fmt_ctxt, NULL);if (ret < 0) {//av_log(NULL, AV_LOG_ERROR, "error occurred when opening output file !\n");goto done;}av_write_frame(fmt_ctxt, &packet);av_write_trailer(fmt_ctxt);}}// okret = 0;done:avcodec_close(codec_ctxt);if (fmt_ctxt){avio_close(fmt_ctxt->pb);}avformat_free_context(fmt_ctxt);av_packet_unref(&packet);sws_freeContext(sws_ctx);av_free(buffer);return ret;
}

借助ffmpeg强大的视频处理和转换功能,我们可以将一帧图像转换成任意格式的图片,当然如代码所示我们只选择性地支持了“jpeg”和“png”两种格式的图片格式;

采用ffmpeg抓图的步骤分两步:

  1. 需要将图像转换成指定的格式,当然强大的格式转换函数也支持图像的缩放,且效率很高;
  2. 图像编码,细心的同学不难发现,ffmpeg的编码和存文件/推送流的代码是通用的,这套代码可以用来抓图也可以用来编码H264、265等然后存文件(如MP4等)或者推送RTMP/RTSP等;

已经完成了抓图代码调用起来就很简单了,只需替换掉旧的抓图函数即可,需要注意的是之前的抓图固定了格式为YUY2,所以缓冲区大小只有WidthHeight2的大小,而显然RGB24格式的数据会导致缓冲区溢出。

所以,我们需要重新定义缓冲区的大小,如下代码所示:

 //抓图if (pThread->manuScreenshot == 0x01 )//Just support jpeg,png{unsigned int timestamp = (unsigned int)time(NULL);time_t tt = timestamp;struct tm *_time = localtime(&tt);char szTime[64] = {0,};strftime(szTime, 32, "%Y%m%d-%H%M%S", _time);//                         char strPath[512] = {0,};
//                      sprintf(strPath , "%sch%d_%s.jpg", pThread->strScreenCapturePath, pThread->channelId, szTime) ;PhotoShotThreadInfo* pShotThreadInfo = new PhotoShotThreadInfo;sprintf(pShotThreadInfo->strPath , "%sch%d_%s.jpg", pThread->strScreenCapturePath, pThread->channelId, szTime) ;int nYuvBufLen = frameinfo.width*frameinfo.height*3;// most size = RGB24, we donot support RGBA Render typepShotThreadInfo->pYuvBuf = new unsigned char[nYuvBufLen];pShotThreadInfo->width = frameinfo.width;pShotThreadInfo->height = frameinfo.height;pShotThreadInfo->renderFormat = pThread->renderFormat ;memcpy(pShotThreadInfo->pYuvBuf, pThread->yuvFrame[pThread->decodeYuvIdx].pYuvBuf, pThread->yuvFrame[pThread->decodeYuvIdx].Yuvsize-1);CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_lpPhotoShotThread, pShotThreadInfo, 0, NULL);pThread->manuScreenshot = 0;}

目前所支持的最大数据格式是RGB24,所以定义了WidthHeight3+1的最大缓冲区大小,其实这里可以优化一下,就是根据具体的renderFormat来定义缓冲区的大小,从而避免不必要的内存资源浪费。

视频流媒体RTSP专用播放器RTSP拉流、RTMP推流方案之EasyPlayer-RTSP-Win抓图代码重构流程介绍相关推荐

  1. 海康大华安防监控网络摄像头网页无插件直播流媒体RTSP专用播放器方案之EasyPlayer-RTSP-Android如何获取拉流的回调?

    EasyPlayer是一个RTSP流媒体播放器,在GitHub上开源大部分源码,其主要功能有播放.抓图.录制视频.实时静音/取消静音. EasyPlayer-RTSP-Android回调InitCal ...

  2. FFmpeg/WebRTC/RTMP/RTSP/HLS/播放器-音视频流媒体高级开发【零声学院】

    FFmpeg/WebRTC/RTMP/RTSP/HLS/播放器-音视频流媒体高级开发 学习 音视频流媒体高级开发学习 01音视频基础 [录播]0-音视频开发高级课程简介(22分钟) 免费试学 [录播] ...

  3. RTSP Windows专用播放器EasyPlayer : 稳定、兼容、高效、超低延时

    EasyPlayer RTSP Windows专用播放器 EasyPlayer RTSP Windows 播放器是由EasyDarwin团队开发和维护的一个完善的RTSP流媒体播放器项目,视频编码支持 ...

  4. 跨平台低延迟的RTMP/RTSP直播播放器设计实现

    开发背景 2015年,当我们试图在市面上找一款专供直播播放使用的低延迟播放器,来配合测试我们的RTMP推送模块使用时,居然发现没有一款好用的,市面上的,如VLC或Vitamio,说白了都是基于FFMP ...

  5. SkeyePlayer RTSP Windows播放器D3D,GDI的几种渲染方式的选择区别

    SkeyePlayer RTSP windows播放器支持D3D和GDI两种渲染方式,其中D3D支持格式如下: DISPLAY_FORMAT_YV12 DISPLAY_FORMAT_YUY2 DISP ...

  6. Android 实现live555 RTSP代理播放器

    简述 利用live555 实现RTSP拉流客户端,但想看下播放效果,所以结合Android MediaPlayer实现播放. live555 实现RTSP交互及拉流过程,然后通过UDP,将数据传递给M ...

  7. vlc播放器或者web实现rtmp拉流

    最简单的拉流莫过于接着第三方播放器了,我们可以利用VLC播放器实现rtmp拉流. 当安装完vlc播放器并且客户端已经在推流了(推流地址为rtmp://127.0.0.1:1935/live/123), ...

  8. RTSP H264播放器(基于live555、ffmpeg、d3d应用)

    最近由于要方便测试流媒体服务器的性能,基于live555.ffmpeg.d3d等开发了一款rtsp h264播放器.当然,只是为了测试,可能会有一些bug,欢迎大家交流. 群:219128816 有需 ...

  9. js调用vlc_vlc播放器或者web实现rtmp拉流

    最简单的拉流莫过于接着第三方播放器了,我们可以利用VLC播放器实现rtmp拉流. 当安装完vlc播放器并且客户端已经在推流了(推流地址为rtmp://127.0.0.1:1935/live/123), ...

最新文章

  1. linux下几种文件系统的测试比较
  2. 100天后 - 100-days-later
  3. ibm服务器虚拟化报价,IBM x86 服务器虚拟化服务.pdf
  4. python中循环结构关键字,04.循环结构
  5. 【论文解读】用Dropout思想做特征选择保证效果,还兼顾了线上性能?
  6. 37 | 案例篇:DNS 解析时快时慢,我该怎么办?
  7. 为排序使用索引OrderBy优化
  8. 基于.NetCore3.1搭建项目系列 —— 使用Swagger做Api文档(上篇)
  9. FreeSql (三十三)CodeFirst 类型映射
  10. Javascript的对象继承方法
  11. 设置Visual Studio code停止自动更新
  12. 响应优先级与zorder
  13. 你爱我,我爱你,IP被封很头疼【Python爬虫实战:ip代理js逆向采集】
  14. 让jquery构造出类
  15. 创建SSH keys用于添加到Git服务器上
  16. Java实现将阿拉伯数字转换为中文数字123=》一二三
  17. 数值分析复习(六)——常微分方程数值解法
  18. ilove中文_iloveyou歌词中文版是什么歌
  19. 计算机word正文样式怎么新建,Word怎么给格式和样式设定快捷键
  20. 网页前端培训(JavaScript)

热门文章

  1. Unicode字符集和多字节字符集关系(一)
  2. 四川计算机专业三本大学排名,四川三本大学排名及分数线2021【文科 理科】
  3. 打开图片计算机黑屏,电脑开机后黑屏怎么办【图文】
  4. linux acl库编译与使用,acl_cpp 的编译与使用
  5. 利用矢网测试PCB走线的特性阻抗
  6. 了解CV和RoboMaster视觉组(四)视觉组使用的硬件
  7. 安卓pkg解包工具_【降级,在安卓数据提取/取证方向上的应用】
  8. 纺织计算机应用技术pdf,计算机图像处理技术在纺织品测试中的应用.pdf
  9. 霸屏系统软件 /超级爆店码/霸屏系统源码
  10. 网站访客系统php,2套网站访客IP黑名单源码有效屏蔽ip(PHP实现,CC防火墙)