当前位置: 首页 > news >正文

网站改域名百度一下京东

网站改域名,百度一下京东,高德能看国外地图吗,做电影资源网站有哪些内容系列文章目录 基于 FFmpeg 的跨平台视频播放器简明教程#xff08;一#xff09;#xff1a;FFMPEG Conan 环境集成基于 FFmpeg 的跨平台视频播放器简明教程#xff08;二#xff09;#xff1a;基础知识和解封装#xff08;demux#xff09;基于 FFmpeg 的跨平台视频…系列文章目录 基于 FFmpeg 的跨平台视频播放器简明教程一FFMPEG Conan 环境集成基于 FFmpeg 的跨平台视频播放器简明教程二基础知识和解封装demux基于 FFmpeg 的跨平台视频播放器简明教程三视频解码基于 FFmpeg 的跨平台视频播放器简明教程四像素格式与格式转换基于 FFmpeg 的跨平台视频播放器简明教程五使用 SDL 播放视频基于 FFmpeg 的跨平台视频播放器简明教程六使用 SDL 播放音频和视频 文章目录 系列文章目录前言线程模型代码说明解封装线程视频解码线程音频解码线程定时器线程 小小的优化参考 前言 在上篇文章中 基于 FFmpeg 的跨平台视频播放器简明教程六使用 SDL 播放音频和视频我们能够同时播放画面和音频。其中 SDL 启动了一个音频线程每次需要音频数据时都会回调到我们定义的函数。现在我们需要对视频显示做同样的事情。这么做能让我们的代码更加模块化更容易使用。 本文参考文章来自 An ffmpeg and SDL Tutorial - Tutorial 04: Spawning Threads。这个系列对新手较为友好但 2015 后就不再更新了以至于文章中的 ffmpeg api 已经被弃用了。幸运的是有人对该教程的代码进行重写使用了较新的 api你可以在 rambodrahmani/ffmpeg-video-player 找到这些代码。 本文的代码在 ffmpeg_video_player_tutorial-my_tutorial04_02_threads。 线程模型 回看目前实现的代码它在主线程做了非常多的事情包括 处理事件循环读取 packet并进行解码显示 frame 因此我们需要做的是让这些工作分开具体的 解封装线程负责从文件中读取 packet并把这些 packet 分配到不同的 packet 队列中视频解码线程从 video packet 队列中读取 packet解码为 frame然后将解码后的 frame 放入 video frame 队列中音频解码线程从 audio packet 队列中读取 packet解码为 frame然后将解码后的 frame 放入 audio frame 队列中定时器线程隔一段时间例如 30 毫秒发送一个事件通知主线程显示视频SDL 音频线程由 SDL 创建通过回调方式获取音频数据进行播放主线程负责各模块的初始化及事件循环。 比较上一章节虽然线程 1 到 4 使事情看上去似乎更复杂了但你可以放心这些线程只是将原来复杂的任务拆分开整体上并没有比之前的代码更复杂。 代码说明 让我们看看每个线程都在做些什么进行代码层面上的解释 解封装线程 std::thread demux_thread([]() {AVPacket *packet{nullptr};for (; sdl_app.running;) {std::tie(ret, packet) decoder_ctx.demuxer.readPacket();ON_SCOPE_EXIT([packet] { av_packet_unref(packet); });// read end of file, just exit this threadif (ret AVERROR_EOF || packet nullptr) {break;}if (packet-stream_index decoder_ctx.video_stream_index) {decoder_ctx.video_packet_queue.cloneAndPush(packet);} else if (packet-stream_index decoder_ctx.audio_stream_indexdecoder_ctx.audio_packet_queue.cloneAndPush(packet);}} });它不停地从 demuxer 中读取 packet并将 packet 放入不同的 packet queue 中 视频解码线程 std::thread video_decode_thread([]() {AVFrame *frame av_frame_alloc();if (frame nullptr) {printf(Could not allocate frame.\n);return -1;}ON_SCOPE_EXIT([frame] {av_frame_unref(frame);av_frame_free(frame);});for (; sdl_app.running;) {if (decoder_ctx.video_packet_queue.size() ! 0) {ret decodePacketAndPushToFrameQueue(decoder_ctx.video_packet_queue,decoder_ctx.video_codec, frame,decoder_ctx.video_frame_queue);RETURN_IF_ERROR_LOG(ret, decode video packet failed\n);}}return 0; });它不停地从 video packet queue 中读取 packet 并进行解码并将解码后的数据放入 video frame queue 中 音频解码线程 std::thread audio_decode_thread([]() {AVFrame *frame av_frame_alloc();if (frame nullptr) {printf(Could not allocate frame.\n);return -1;}ON_SCOPE_EXIT([frame] {av_frame_unref(frame);av_frame_free(frame);});for (; sdl_app.running;) {if (decoder_ctx.audio_packet_queue.size() ! 0) {ret decodePacketAndPushToFrameQueue(decoder_ctx.audio_packet_queue,decoder_ctx.audio_codec, frame,decoder_ctx.audio_frame_queue);printf(%zd \n, decoder_ctx.audio_frame_queue.size());RETURN_IF_ERROR_LOG(ret, decode audio packet failed\n);}}return 0; });它不停地从 audio packet queue 中读取 packet 并进行解码并将解码后的数据放入 audio frame queue 中 定时器线程 我们使用 SDL_AddTimer 来创建一个定时器参数解释 interval定时器的间隔时间单位为毫秒。callback定时器结束时调用的函数。这个函数的原型必须如下Uint32 callback(Uint32 interval, void *param);param传递给回调函数的参数。 static Uint32 sdlRefreshTimerCallback(Uint32 interval, void *param) {(void)(interval);SDL_Event event;event.type FF_REFRESH_EVENT;event.user.data1 param;SDL_PushEvent(event);return 0;}我们的定时器回调函数 sdlRefreshTimerCallback 它向 SDL 发送一个 FF_REFRESH_EVENT 事件主线程在接收到 FF_REFRESH_EVENT 事件后将会从 video frame queue 中 pop 一帧数据进行图像格式转换操作并使用 SDL Render 将其渲染到屏幕上。最后会再次启动一个定时器用来刷新下一帧。 小小的优化 现在各自线程处理各自的事情解封装线程是数据源头该线程在一个 for 循环中源源不断地读取 packet后续的解码线程也在源源不断地解码数据。我们播放一个 30fps 的视频大约每 33.33ms 播放一帧视频而解码的速度比 33.33 快多了也就是说现在的线程模型会会囤积非常多视频数据等待被播放。这是对内存的一种浪费我们不需要缓存这么多的视频帧。 解封装线程是所有数据的源头我们只要控制住源头的速度就能够控制整个 Pipeline 的速度。因此我们在解封装时对 packet queue 中的数据存量进行检查如果超过某个阈值那么就让解封装线程 sleep 一会控制下 pipeline 的速度。 std::thread demux_thread([]() {AVPacket *packet{nullptr};for (; sdl_app.running;) {// sleep if packet size in queue is very largeif (decoder_ctx.video_packet_sync_que.totalPacketSize() DecoderContext::MAX_VIDEOQ_SIZE ||decoder_ctx.audio_packet_sync_que.totalPacketSize() DecoderContext::MAX_AUDIOQ_SIZE) {std::this_thread::sleep_for(10ms);continue;}std::tie(ret, packet) decoder_ctx.demuxer.readPacket();ON_SCOPE_EXIT([packet] { av_packet_unref(packet); });// read end of file, just exit this threadif (ret AVERROR_EOF || packet nullptr) {sdl_app.running false;break;}if (packet-stream_index decoder_ctx.video_stream_index) {decoder_ctx.video_packet_sync_que.tryPush(packet);} else if (packet-stream_index decoder_ctx.audio_stream_index) {decoder_ctx.audio_packet_sync_que.tryPush(packet);}}});参考 An ffmpeg and SDL Tutorial - Tutorial 04: Spawning Threadsffmpeg_video_player_tutorial-my_tutorial04_02_threads
http://wiki.neutronadmin.com/news/378315/

相关文章:

  • 深圳做网站(龙华信科)网络营销管理
  • 手机网站模板网opencart做外贸网站怎样
  • 网站做推广团队wordpress上传不了图片
  • 昆明著名网站建设网站开发实验报告模版
  • wordpress 网站导航企业融资计划书范本
  • 深圳网站设计联系电话怎么注册个人工作室
  • 网站游戏制作开发网站建立要多少钱
  • 有没一些网站只做临床药学公众号怎么链接wordpress
  • ps制作网站首页江西南昌网站建设哪家好
  • 网站系统安全性网页编辑招聘
  • 动态图片素材网站百度公司地址在哪里
  • 凡科轻站小程序怎么样公司网址格式怎么写
  • h5网站的好处wordpress 网站标题图
  • 做网站 用什么做数据库最好企业网站导航代码
  • python 电商网站开发地推网推平台
  • 网站开发模板教务管理巴中网站建设有限公司
  • 自己做背景的网站苏州区网站建设
  • 淮安官方网站开发区深圳网站营销公司
  • 泉州网站排名优化企业网站的主要栏目
  • cc后缀网站菏泽网站建设哪好
  • 做网站云服务器选择多大带宽旅游景点网站建设
  • 哪个网站做外贸的多山东东营市东营区邮编
  • 内容营销概念北京网站优化wyhseo
  • 旅游网站开发的国内外现状广州越秀区天气预报15天查询
  • 怎么参考已有网站做新站网页软件有哪些
  • 茂名建站模板搭建精品网站建设费用 找磐石网络一流
  • 网站空间购买官方唯品会网站建设建议
  • 苏州网站定制公司哪家好海外社交网络推广
  • 哪个公司做网站便宜wordpress自己写界面
  • 网站开发的流程seo助手