1.添加进度条的滑动与释放


将信号sliderPress()与槽SliderPress()连接
将信号sliderRelease与槽SliderRelease()连接

2.完成进度条跳转

,并在xplay2.h将这两个槽放在public slots:中:

void Xplay2::SliderPress()
{isSliderPress = true;
}

seek会造成极大的开销,假如seek到一个P帧,其参考的I帧与其距离50帧,则要解码50帧,若每seek一点都进行一次解码,这是不现实的,因此我们选择当seek结束时进行解码`

void Xplay2::SliderRelease()
{isSliderPress = false;double pos = 0.0;pos = (double)ui.playPos->value() / (double)ui.playPos->maximum();dt.seek(pos);
}

在解封装线程添加seek来直接访问解封装类的接口:

void xdemuxthread::seek(double pos)
{mux.lock();if (demux)demux->seek(pos);mux.unlock();
}

seek时代码调用逻辑:
01.当用户拖动进度条的行为结束时调用Xplay2的SliderRelease()函数,该函数中通过在qt中进度条拖动的值除以进度条的最大值获得一个比例pos:

pos = (double)ui.playPos->value() / (double)ui.playPos->maximum();

然后通过dt.seek(pos)将pos传给解封装线程
02.在解封装线程中将传进来的比例值pos乘上解封装上下文中的视频流的总时长,获得要seek到的pts,再使用ffmpeg提供的接口av_seek_frame进行跳转:

long long seek_pos = ic->streams[videoStream]->duration * pos;
int re = av_seek_frame(ic, videoStream, seek_pos, AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME);

注意:1.这是跳到关键帧,而不是实际的帧,这是解封装的函数,根据单一职责将跳转到实际帧(涉及解码)的任务交给到外部业务
2.为什么使用视频来seek?因为若使用音频来seek的话对应的视频可能seek到非关键帧,比如P帧,P帧的解码需要I帧,此时将会使用错误的I帧进行P帧解码从而导致花屏
3.使用AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME向后找

03.此时在解封装线程中用个while(true)循环进行seek的等待,在这个循环等待中,会不断拿到解封装的pkt,当拿到的pkt中的pts大于等于想要seek到的pts时才开始播放:

if (decode->pts >= seekpts){if (call)call->Repaint(frame);vmux.unlock();return true;}

3.解决卡顿

此时拖动进度条发现过一段时间画面才切换过来,这是因为还有缓冲还未用完,因此在seek使调用解封装的clear,在这个clear中再调解封装的clear和视频音频线程的clear:

void XDemuxThread::Clear()
{mux.lock();if (demux)demux->clear();if (vt) vt->Clear();if (at) at->Clear();mux.unlock();
}

解封装的clear:

void xdemux::clear()
{mux.lock();if (!ic){mux.unlock();return;}avformat_flush(ic);mux.unlock();
}

音频线程的clear要比视频线程的clear多清理一个audioplay,因此视频线程的clear调用其基类xdecodethread的clear:

void xdecodethread::Clear()
{mux.lock();if(decode)decode->clear();while (!packs.empty()){AVPacket* pkt = packs.front();XFreePacket(&pkt);packs.pop_front();}mux.unlock();
}

音频线程调用自己重载的clear:

void xaudiothread::Clear()
{xdecodethread::Clear();mux.lock();if (audioplay) audioplay->Clear();mux.unlock();
}

其先调用其基类的clear,再清理其audioplay:

 void Clear(){mux.lock();if (io){io->reset();}mux.unlock();}

同样,这是工厂模式产生的类,需要在其工厂中将其声明为纯虚函数:
virtual void Clear()=0;

现在seek后没有卡顿,但是不会在seek位置准确播放

4.解决进度条的跳转

位置不精确是因为demux里的seek策略导致的:
av_seek_frame(ic, videoStream, seek_pos, AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME);
将会导致实际seek到的位置在想要seek的位置偏左
因此我们需要在seek之后用循环来判断当前解码到的pts与想要seek到的pts的关系,当解码到的pts大于等于想要seek的pts时才会将音视频播放:

seekpts为想要seek的pts,decode->pts为实际的pts

void xdemuxthread::seek(double pos)
{Clear();mux.lock();bool statuspause = this->isPause;mux.unlock();SetPause(true);mux.lock();if (demux)demux->seek(pos);long long seekPts = pos * (demux->totalMs);while (!isexit){AVPacket* pkt = demux->readfz();if (demux->isvideo(pkt)){if (!pkt) break;if (vt->RepaintPts(pkt, seekPts)){this->pts = seekPts;break;}}else{XFreePacket(&pkt);}}mux.unlock();if(!statuspause)SetPause(false);
}

关于if (vt->RepaintPts(pkt, seekPts)):
根据seek到的pts与实际想要的pts来判断是等待还是直接绘制
等待时RepaintPts返回false,然后进入下次while
绘制后RepaintPts返回true,然后更新当前的pts

关于暂停:
不管seek前视频是否为播放状态,则seek前统一暂停,不然如果正在播放的话解封装线程在seek,其他线程仍然在做解码,会出问题。如果seek前为播放状态,则seek结束后恢复播放,如果seek前为暂停状态,则seek结束后仍暂停。

关于XFreePacket(&pkt):
在demux的seek策略中选择的是使用视频来做seek,因此当读到的packet为音频时直接清空这个packet,如果是视频的话在send之后完成了对pkt的清理。
本模块包含了decode模块,decode中包含了ffmpeg库,av_packet_free(pkt)需要使用ffmpeg库,这里想减少与ffmpeg库的耦合,便在decoder中将av_packet_free(pkt)封装起来,在本模块中调用封装后的函数即可

void XFreePacket(AVPacket** pkt)
{if (!pkt || !(*pkt))return;av_packet_free(pkt);
}
bool xvideothread::RepaintPts(AVPacket* pkt, long long seekpts)
{vmux.lock();bool re = decode->send(pkt);if (!re){vmux.unlock();return true;}AVFrame* frame = decode->receive();if (!frame){vmux.unlock();return false;}//到达位置if (decode->pts >= seekpts){if (call)call->Repaint(frame);vmux.unlock();return true;}XFreeFrame(&frame);vmux.unlock();return false;
}

该函数一直到decode->pts >= seekpts都返回false,即seekpts之前的音视频都不会播放,并且使用XFreeFrame(&frame);/释放掉指向位置之前的frame。

此时完成了移动滑动条到指定位置播放

播放器实战27 完成seek到指定位置相关推荐

  1. 播放器实战28 总结

    至此,播放器的基本功能已经实现,进行一个总结: 一,仅进行播放时的函数调用流程 只做一个大致的梳理且不涉及seek等操作): 01.QT中的整个控件为QWidget类,Xplay2类为其继承,在mai ...

  2. 基于 Vue 的直播播放器实战

    原文地址:点击进入 前言 时下直播的盛行让很多人对直播技术产生浓厚的兴趣,orange 本人也不例外,本文借着实战的目的完成一个 demo,并没有深入的讲解直播技术的实现原理以及推流和拉流的实现,为什 ...

  3. vue 判断同一数组内的值是否一直_前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目

    项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...

  4. vue实现音乐播放器实战笔记

    一.项目说明 该播放器的是基于学习vue的实战练习,不用于其他途径.应用中的全部数据来自于 QQ音乐 移动端(https://m.y.qq.com/),利用 jsonp 以及 axios 代理后端请求 ...

  5. 后端实体类接收数组_前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目...

    项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...

  6. 前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目

    项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...

  7. 播放器实战07 av_read_frame与av_seek_frame

    一.了解结构体AVPacket与AVstream AVPacket: AVBufferRef *buf :buf指向一个空间,该空间里存放引用计数,packet每次copy的时候引用计数+1,每次删除 ...

  8. 妙味课堂H5音乐播放器实战视频课程 ajax实战教程

    课程介绍: 本次课程涉及的知识点包括移动端H5.CSS3.JS.滑屏.HTTP协议.AJAX.跨域.前后端交互.PHP.mySql.jQuery--配合这些知识点,讲师写了一个H5播放器demo,用来 ...

  9. 播放器实战19 Xaudio打开音频

    1.xaudio.h #pragma once class xaudioplay {public:static xaudioplay* get();xaudioplay();//一定得是虚析构函数,d ...

最新文章

  1. 软件测试培训 高级测试/测试开发基本技能列表
  2. EdgeGallery — OpenStack VIM
  3. 负载均衡下ajax第二次请求,会话清除第二个AJAX电话
  4. Linux疑难杂症解决方案100篇(十一)-ubuntu crontab 详细规则及不执行时的解决方法
  5. less的一些用法整理
  6. Elasticsearch实战:给博客打造全文检索
  7. 文件操作(上传,下载,限制)
  8. java 打印ascii字符串_简单使用JAVA打印纯ASCII字符构成的酷图效果
  9. DMA—直接存储区访问
  10. elementary os java,吐槽ELEMENTARY OS系统/ELEMENTARY OS系列文章汇总
  11. 【matlab】ode45求解二阶微分方程,绘制曲线图 | 使用函数句柄的方法
  12. 关于Angular样式封装
  13. Python学习笔记(正则表达式)
  14. ArcGIS Engine开发之旅01---产品组成、逻辑体系结构
  15. C语言开发环境搭建及调试
  16. JSchException: Algorithm negotiation fail
  17. 证券业上云内参: 深圳证券信息
  18. 零死角玩转stm32初级篇5-流水灯的前后今生
  19. 神经网络模型文件后缀名,神经网络模型文件格式
  20. [创投新闻] [中英双语] FACEBOOK为美竞选上线电子投票功能并开通选民信息中心

热门文章

  1. 模拟信号和数字信号讲堂(二),模拟信号和数字信号之数字信号详解
  2. 铁三角发布 BP3600 沉浸声录音话筒
  3. 简要介绍VGA、DVI、HDMI三种接口之间的关系
  4. YOLOv5+DeepSort多目标跟踪教程
  5. win7 IIS配置
  6. 教师学python有优势吗_学Python有意义吗 就业前景如何
  7. BlueTooth: 蓝牙协议栈实现模式分析
  8. 设置 tooltip-popper 宽度
  9. 网管员职业规划专家问答
  10. Camera Link协议和FPGA的数字图像信号源设计