音视频开发学习一年总结:从入门到实践

1. 学习背景与动机
  • 为何选择音视频开发

        当时刚上大学,只知道蒙头学计算机编程的一些基础,从翁凯老师的C语言 --> 黑马的C++300节课 --> 网上各种的网络编程基础,这些通用的东西学完之后,就去看C++基础上,有没有什么好的方向;

        人有时候做选择啊,太低了看不上、太高了又觉得够不上,所以选择往往都会偏向中等,而音视频在整个行业中,也算是位于这样的一个层级了,大多数从业者的35岁危机,可能少一点,没有像网上的其他行业人员大面积报出来这样一个“危机”的信号,收入和嵌入式一样,越老越吃香吧。

        大学阶段选择的是相对偏软件的专业,所以本身接触硬件的机会很少,也是犯了先入为主的错误,在大学选择方向的阶段,本能地觉得嵌入式这个行业,要去接触和硬件相关的一些列东西,比如:电路图、电路设计分析、原件焊接、自己出钱买东西······,而相对的,如果是偏软件方面的东西,它往往只需要一台能够连接到外网的笔记本即可,就从这个角度而言,最终也是在 “嵌入式” && “音视频开发” 中选择了音视频这样的一个方向。

  • 初始技术栈与知识储备

        选定方向之后,就是去找相应的课程和路线了,b站上有个 “北小菜” 的up主,它的视频中有关于音视频方向的学习的路线以及建议:北小菜的个人空间-北小菜个人主页-哔哩哔哩视频,这是它的b站个人主页,有兴趣可以去瞧瞧!

        基础的行业了解以及行业所需的基础技能的学习,肯定是需要一套较为系统的教程的,对于我这种在校的“穷大学生”而言,那些网上动不动就过万的课程,嗯···,买不起,不是我的钱,画得肯定不得劲儿,所以我选择去网上找各种各样的资源,这里啊,推荐一下,嗯,pdd,嗯,上面的东西在其他网站上都是有的,只不过没有人给你系统性地总结出来,在上面买,还是比较划算的,两天的饭钱而已。

        另外github上也有对应的学习仓库:0voice/awesome_audio_video_learning: 2025年音视频开发最新总结,提供全面的音视频开发学习资源,涵盖从基础知识到实战项目的资料、论文、书籍、项目和示例,帮助你快速热门并逐步进阶,持续更新维护中!

这是零声教育发布的一个学习指南,这也是我比较推荐买课的同学,去关注的培训机构,因为市面上,做这一方面的机构,很少,系统性的讲解相关方面知识的人,就更少了,铃声还行吧,自己看着办,反正知识就那么多,学到就是自己的。

2. 学习历程
  • 初期:

        在通过网上的各种视频学习之后(只看了基础部分),尤其是 ffmpeg 的部分,几乎从我接触音视频这个方向以来,很多想法的实现,都是依靠 ffmpeg 来进行的,或者说对于音视频的很多东西,都是围绕着 ffmpeg 来进行具体的展开的,在这个过程中实现了很多简易的功能,比如:编码、解码、转码、滤镜处理、+SDL渲染video/audio、······,也就是在去年8月份,到现在也快1年了吧,实现了一个简单的 “推流程序”,支持保存到本地的这样的一个东西,根本就没有考虑性能方面的问题,基本遵循着先能用、然后再优化的策略,嗯,我感觉这样学习是比较符合人的一个学习过程的,相比较于先啃一大堆理论,然后再去实践,这种方式算是成本相对较低的了。

  • 中期停滞

        起因:

        上了大学你也知道,身边的同学不管是宿舍也好、班级也好,基本都在玩,没有真正的几个人去系统学习的,就算有,也基本是卷绩点、卷保研的,我在大学刚开学时,进入了一个社团,也算是整个学校里最专心搞计算机的一个群体了,在那里,认识了一位学长,我叫他“波波学长”,哈哈,很多的计算机规划,或者说是大学的一个整体的规划,都是和他进行讨论的,当时我大一下,对未来其实还是比较迷茫,参考他当时的一个状态,在本科阶段,跟着一个学校里的导师,做项目、发论文,这吸引到了我,我开始去思考,我是否也能够去跟着这么一个导师呢?在兼顾我本身努力的方向,同时去做一些和学术相关联的事?

        思考:

        因为当前的计算机学术圈的大方向,基本全部都是和神经网络有关的,所以我去找了晚上的很多信息,去看,发现有一个机器视觉的大方向,关键是“视觉”,这听起来好像是和音视频沾了一点边的,所以直接就去找相关方向的导师,有,而且人家确实想要找这么一个本科生,经过学长的推荐,也是去了,刚开始嘛,一个大学生,对于感兴趣的事务有着基本的、饱满的热情,在电脑上跑模型、训练、标注数据集、······,那时候,早上没课7点去图书馆学习音视频的知识,敲代码,一直到晚上19点吃饭,回去继续学 AI、神经网络相关的东西,时常是学完、敲完代码、配置好训练参数,已经是凌晨2、3点了,哎~,但是很充实(这个烂大学,那时候还有早操,3点睡,6.30就得起,不去教务处直接发处分通知,我真是***,导员跟催命似的,好像不跑操,天就塌了一样,这样的生活持续了3个月)。

        终于,扛不住了,那是一天下午,坐在图书馆,外面的天黑得像是能将整个天地,都染成一个大黑缸,潮湿的空气透过玻璃,直冲人的天灵盖,明明是大夏天,居然让人有种面对世界末日,无能为力的粘稠、阴冷的感觉。不知为何,头顶的白炽灯,突然间灭了、毫无征兆、周围陷入一片死寂,我回过神来,想继续去学习,可是冷汗一层一层的往出冒,那是种什么感觉呢?

        在梦中的死胡同里,独属于中国风的僵尸明明上一刻还在入口处,只是愣神之间,便已致眼前,那模样就像是中药里熬干了的药渣捣碎浸泡、烘干后的样子,就像是深棕色的树皮有了弹性一样,狰狞脸庞的右半部分还有深色的血渍。到此便戛然而止,猛地睁眼,房子里静得吓人,但门却是大开着的,那股凉意从脚底一直传递到头皮上,震得人失去了思考的能力。

        但是现在这种状态,就像是确定了一件不好的事终于发生在眼前了,那种从心脏迸发而出的“冲击波”,瞬间席卷了全身,从头部到脚底,脚底板就像是粘连到了一大块冰块上面,冻到人失去了脚部的知觉。

        不行!我要去窗口透气,现在就去。窗口距我仅有两个座位的长度,一步便到,大口大口地呼吸着新鲜空气,好像那个元婴老怪一口吸干整个天地的灵气一般,心悸的感觉不再有,冷汗也止住了,可怜后背的短袖,像是刚被从运转的洗衣机中拽出来的一样。

        抬眼看去,那面旗帜就这么在风雨中飘扬着,在那即将“塌”下来的、深至天际、如墨汁浸泡般的黑云和地上的人们之间飘扬着,或者说,矗立着,仿佛只要有它在,这天即使真的“塌”下来,也有它顶着!心逐渐安静下来,那股不可名状的不安感,随着天地间矗立的这抹红色,消散了~

        刚才突然间的举动,恐怕在这种自带安静属性的场所炸开了锅!回头看去,幸好,18点了,都去吃饭了,为数不多的几个考研人都在两端坐着,他们戴着耳机,想来也不曾被打扰。

        哎,看来身体已经出问题了,不能再这样熬下去了,我开始反思:我自从上大学以来,一直是处于一种高度紧绷的状态,我给自己的压力太大了,就像是被大厦般体积的棉花,压在我的身上,不至于瞬间暴毙,但呼吸的权利好像被剥夺了一样。

        我要减负,把身上的东西往下搬,直到它和我的生活平衡为止,其中占比最大的一个就是跟着这位老师做项目,它几乎沾满了我的整个晚上,并且成果不明显甚至于让我有种做不好天就塌下来的感觉,我讨厌这种感觉,就像是拿刀架在我脖子上,那股无名的愤怒在胸中回荡,可是细细想来,是我主动要去做的,没有谁逼我,做的好与不好和老师也没有太大的关系,或者说,人家根本不在乎,也,不需要在乎。

        让我来捋一捋,我出于想要将神经网络和音视频结合起来的想法,去寻求一位学术上的老师的指导,跟着他们的步伐走,学习我需要的技术,然后去完善我自己想要做出来的项目,可是就当前来看,从老师这里根本获取不到现成的,可以借用过来的知识,很多东西都是以“论文”的形式,或者说“学术”的形式展示出来,想要落地使用,我自己就得不断去摸索,哎~想到这里,就算我不跟着老师学习,我也能够自己去做这些事,而且没有任何区别。相反的是,跟着老师就得去做一些他手下的项目,而这些项目,用到的知识,我得重新学,用到的数据集甚至都不完整,哎~,做出来的效果肯定也是一塌糊涂,这完全和我最初选择方向不一致,正反馈更是一点没有,并且身体也熬了太久了,嗯,念及于此,走吧!

        给老师发了很长一段信息,嗯,老师只给一句:好的,有事及时联系。嗯?怎么一股AI味?有时候老师让我给某篇论文给指导建议,我都是直接摘取其中的实验结果让AI替我给的,然后老师把这个指导建议,直接给要指导的学生了?????好吧,有点荒谬了是吧,形象点来说就是:一个大字不识的农民,被要求点评一名研究生的论文?????有点好笑了,这位学长不会拿着AI给的建议,然后又去问AI,“请结合老师给我这篇论文的建议,指出我应该修改的论文的点,或者说,你直接帮我修改”,哈哈哈,我一想到这个画面就忍不住了。

        好了,言归正传,经历了这么一场对学术的祛魅,也算是认清现实了,一个人的精力终归有限,只能在有限的时间中,做力所能及的事,把太多的担子压在身上,最终吃不消的,只会是少年单薄的肩膀,消磨的,是少年面对万事万物的激情。如果你也有类似的状态,请先停下来想一想,你能走下去吗?你的身体撑得住吗?

  • 当前状态

        从繁重的事务中抽身出来后,每天也不想着考研的事,只关心音视频这一个方向,心理的压力少了很多,那天之后,我终于有充足的时间可以去睡觉了!

       1、 简单推流器,仓库位置:emmasi3/ffmpeg_recoder_2024: 学习阶段的音视频采集并编码到本地文件_推流到rtmp_server

但是呢,遇到了一些问题:比如,一旦将帧率设置为25fps及以上,音视频根本不同步,本以为是策略问题,在网上找了很多博客,也试过很多,但是结果都不近人意,其中一个最显著的特点:
录制下来的mp4视频,在30fps下,视频里面的事件发生的速率远远大于正常的事物发生速率,这个原因在我的博客:FFmpeg+DXGI:解决GDI录屏音画不同步-CSDN博客中有分析过程,并且我自己后续的行为也证实了我的观点。

并且该推流器,在运行时,CPU占用非常高,都快40%了,这肯定不行,录个屏而已,电脑风扇都快转冒烟了?所以才想着去改进项目,但是因为那是我第一次写一个功能集成型的项目,功能全部都堆在一个类中,很臃肿,让人看都不想看了,所以去写了另一个项目;
        2、up主北小菜的高性能rtmp服务器,对于音视频流媒体方向上,我最初的规划:

嗯,看起来还行吧?其实最主要的就是服务器,我在这方面,根本就是啥都不懂,当初在学习网络编程的时候,只听过 epoll、reactor、···在高并发服务器上被经常使用,我只知道这些东西非常高效,但是具体高效体现在哪?我没有概念,所以我急需一个现成的例子,帮我去了解。ok,有的兄弟有的,在b站上有这么一个服务器案例,嗯,好像还需要往up主的某一个网站上冲5块钱???我有点遗忘了,比较快一年了;

阅读源码的感受:懵圈了,根本不知道这里为什么要那么做?这里又是什么C++语法?调试时为什么一个类的构造函数能嵌套这么多的构造函数,点的我快“迷路”了?·······

很明显,我恐怕还不具备阅读大型项目的知识储备和经验,服务器中用到的很多定时器、线程池、内存池、单单拆开来看,我都能懂,但是他们组合起来之后,为什么是那样?为什么要是那样?没有一个合适的解释,或者说,就单靠我现有的知识储备,不能够理解。我需要的是一个从0到1的开发教程,哪怕性能不那么好,只要这个体系设计能够入门,那么剩下的东西,无非就是往深了研究的事情了,现在就相当于,在源码中屋头的苍蝇,乱飞!


        3、sylar C++高性能服务器:
        这是一个在6年前由sylar本人写的一个开源项目,也是我开始理解服务器,不!不只是服务器,还有整个学习体系的起点!

        课程一共有 80 节,每一节课都干货满满,我开始从学完黑马C++课程中的迷茫感中走出,在这里,我可以看见前人使用那些简单的 C++ 语法,构建出来一整个体系的全流程,说实话,很震撼,每一节课我都得学习好久好久~,那些我砍死学过的知识点,在大佬的书写下,变得陌生且充满艺术感!刚开头的“日志系统” && “配置系统” 简直是打破了我之前的编程体系的理解,原来代码还可以这样使用!原来模块还可以这样搭建!原来简单易用的API内部需要这么多组件进行支撑!······

        我看完整个80节课,已经是7个月之后了,说实话,很难!太难了,即使有 AI 辅助我理解,我依旧要学习很久,我到现在都不敢说吃透它。

        这让我想起大学刚来那会,一直看 翁凯老师的 C语言,当时我对我的路其实还是很迷茫的,不知道要做什么,只知道,这个课很多人都看,所以我也看,每天强制要求看10节课,到后面其实只剩下煎熬了,这是一种状态;

        之后学习黑马的 C++ 课程,学到后面,就剩下一些常用的 C++ 中的工具了,到现在,我都没有使用很多,当时的我其实很早意识到过这个问题,就是很多东西其实都用不上,到音视频学习也好,这三种学习过程中的状态是什么呢?

总结一下:别人在视频中,将饭弄好,味道你嘴里,但是要我自己做这些饭,或者将这些饭有机组合起来,做成一桌子菜,有深度的菜,不是能不能实现的问题,而是,没有参考,你不知道你这一做,得做多长时间?什么时候完成?做的效果好不好?他会让初学者产生一种“恐惧感”,久而久之,如果没有主动去经历一场大的由自己做成的一件事、一个项目、一个产品,他就会逐渐失去主动去探索、实践的勇气!简而言之,他会逃避这件事,逃避的最佳手段是什么?“吃别人喂到嘴里的饭”!这些课程也是一样,在你有了对一个行业、一个产品最基本的、掌握基本工具的使用之后,一定要去实现一些想法,也就是从0到1,做一个东西出来,哪怕做的一塌糊涂,很烂,但是效果却能够出来,这就够了,这也是一种自我肯定的手段,检验一下学习的成果。所以看课也好,还是其他的行业,要有这个自信,去实践,这样才能走得远,否则怪圈会越画越大,直到把人吞没为止!

        4、DXGI高性能推流器;

        这是在今年做的,也是刚做完服务器,我在做完这些之后,对音视频、服务器行业已经大概有了一个判断,所以计划是:推流端(高性能) + LinuxRtmp流媒体服务器 +  SDL高性能播放器(拉流器);我想做到这三步,实现一个类似与直播的全流程,这个路线和上面的照片是一回事,这路走了很久。

        回到这个推流器,其中最然我苦恼的地方是,“录屏”这个操作,ffmpeg 默认支持的 GDI,它的性能实在是太差了,我对整体项目的期待仅仅是能够稳定运行、有足够的亮点以便于面试时需要、耗费系统资源低。

        看网上很多都说,DXGI技术,我去了解了一下该技术,是微软DirectX框架中的一个核心组件,其中有一个IDXGIOutputDuplication接口,专门负责屏幕捕获,我最开始对他的理解是:一个低延迟的捕获组件或者是“截屏”组件,对!关键是我以为他和 GDI 一样,都是采用 “截屏” 操作,来实现 “捕获” 这一功能的,只不过它的 “截屏” 操作比 GDI 更高效,耗费系统资源更低,最后在实际处理捕获的视频帧时,才发现,不是这么一回事,在 windows上,很多的应用、软件程序,如果需要通过GPU渲染画面到屏幕上,底层必然要通过DirectX2D提供的 present() 接口,将一帧数据发送到GPU可访问的区域,而IDXGIOutputDuplication在捕获的时候,不是像 GDI 那样,直接复制整个位图,而是直接通过索引在 GPU 显存中访问它,0拷贝!这也是它为什么高效的重要原因!至于后续如何将这个 GPU 中的帧送到 GPU 中进行硬解码?或者说为了方便,直接调用 Map() 将这一帧数据从显存中拷贝到 CPU 可访问的内存中,是开发者自己的选择,效率都是非常高的,比 GDI 高多了,为什么效率高,能够解决我之前所说的视频速率加快的现象,那篇博客中有说!

        测试所用工具:Nginx -- rtmp服务器分发,VLC拉流段拉流
        测试的效果:在多个拉流段的测试下,音视频始终同步、直播延迟为1~2s,程序运行流畅,嗯嗯,达到心理预期;
        存在的问题:(1)由于之前所学习的课程中,对于 C++ 的带引用计数的智能指针的了解有限,导致使用起来真和使用裸指针的方式一样了,做了很多任性的设计,我现在就能回忆起来的问题就有一个“循环引用”的问题,最近在忙最后一个项目,实在是没有时间去修复了,用AI我又不太放心,先就这样吧;
        (2)由于将 GPU 显存中的视频帧 “直接” 送到GPU中编码,不经过CPU,所以需要一个硬件帧池这样一个东西,存储临时的显存中的帧,合理的流程应该是:capture获取帧 --> 处理脏区域 --> 加上鼠标图样 --> 通过GPU内部进行帧拷贝,拷贝到显存中的另一个区域,也就是缓存起来,防止 GPU 异步编码时,在外部发生帧被释放的尴尬事情,对吧?所以要有一个环形队列去缓存这些帧,但是我当前项目的流程:capture获取帧 --> 帧会被自动放入 HwFrames 池子中 --> sendGPU异步编码,这会导致什么问题呢?
        如果这个 帧池子 容量本身太小,而将其中的帧 送去 GPU又不是立即编码的,中间会有一个延迟,假设:容量为8,索引为 5 的帧,被送入编码,但是还没有被编码的时候,池子中的 5 号帧,已经被capture捕获的另一帧覆盖了!但是不会没有数据,对吧?好,那么之后的是也就很好猜了,视频一直出现瞬间的回退现象,我还有以为是我眼花了,为止我还特意去查了一下“人眼最快反应速度”,文章中表示,人眼要识别快速变化的一瞬间的东西具体是什么(我的测试视频都是用浏览器上的北京事件字样做的),需要至少120ms,而人眼如果仅仅是反应取片区域尤其是亮度的巨大变化,仅仅需8~16ms,所以那样的一个错误在1s的变化范围内,出现了至少一次,我是能够察觉到的,所以我猜反推问题到根源,嗯,如果用一个队列,而不是用一个只能保存索引的缓冲区,问题才能够逻辑上就被解决了,但那样要动很多东西,发现这个问题的时候,项目已经写好了,哎~下次要记得60、80、120fps都测试一下啊!!!

那么我的临时性的解决方案:既然是因为异步编码之前,帧被覆盖了,那简单,扩大这个硬件帧池紫的容量大小,让他通过遍历的方式去更新桌面帧的长度增加,那么之前5号帧是不是就能够存活更长时间而不被覆盖了?应该能够解决,如果我的思路正确,那么推论一下:25fps、60fps、120fps,用户一般来说,对于一个直播场景,帧率要求不会太高,120fps已经是很少的了,大多数都是60或者30左右,所以帧池子的容量只要能够满足高帧的录屏,也同样能够满足低帧的录屏,最后的效果和我的分析也一致,并且从任务管理器中发现的进程占用内存的资源也很稳定,没有太离谱。好了,这些问题,都以后解决吧。

        5、rtmp服务器,该服务器是在学习sylar服务器框架的基础上,通过添加北小菜中 rtmp 处理模块,综合起来的一个服务器,事件处理器等逻辑,都是在 sylar基础上进行的,北小菜的rtmp处理模块仅作为一个工具,如何处理rtmp事件的分发是才是重点,说实话,该课程仅仅讲解了在服务器基础上快速搭建 http 模块,成为一个 http 服务器,本来想着将常见的流媒体协议都实现一遍,也方便我学习这些协议,但是目前来看,还是先做好rtmp服务器的搭建为好,其他协议,和这些东西也差不多,区别只是他们的服务方式,有时间做 -- http-flv、hls、rtsp、rtp、基于udp的游戏服务器。

        在移植过程中,碰到了很多问题,这里挑一个我印象最深的:

        问题现象:rtmp 发送数据包过程中,服务器直接触发断言?提示:该fd已经注册过 w 事件,额,后续查看问题,发现是 rtmp 在一次发送过程中,对于同一个 fd,通过 hook 后的 send 方法,首先发送了一段数据,然后他还要在进行一次发送,也就是在一次发送逻辑中调用了两次send方法,其实按照正常人的思路,这有问题吗?没问题,是吧?但关键是该服务器当初设计的时候,只考虑在一次请求过程中,调用一次 send,也就是注册一次  w 事件,方便管理,也就是说,他不支持连续两次调用send,在hook后的逻辑中,每调用一次,都是在尝试注册事件,不能够再一次交互中注册两次,我们认为不合理,那么合理的解决思路:

        不修改 rtmp 应用层发送的逻辑,改变服务器底层对于事件注册的架构,为每一个 fd 连接维护一个信息队列,支持在一次交互逻辑中多次累计信息,最后一次性发送,这样做,无论应用层的 rtmp 或者其他协议如何调用 send,事件只被注册一次,你要发什么东西,分多次给我,然后底层帮你一次性收发。

        但是我不想去修改,或者说现在去修改底层逻辑,能不能对 rtmp 应用层做限制呢?思路:rtmp 在一次调用中的所有send操作,不在是调用底层的 send 方法,而是调用 rtmp 自己的 send 方法,将所有的 io 操作的数据都统一存放,只在最后由 rtmp 自己的发送模块去调用底层的 send 一次,这样做,仅仅注册一次,也可以解决问题。
        这两种方法,前者使其兼容度更高一点,但是都是能搭建服务器的开发者了,添加一个这样的send模块很难吗?

        6、QT高性能播放器,本来的想法是用 SDL 做一个有界面的通过键盘事件去操作音视频的这样一个逻辑,但是进度条seek功能好像有点难以做到,因为这必然涉及到一个UI的界面展示,并且我的想法是做一个和 b 站这个本地播放器差不多的这样的一个项目,并且还要支持rtmp拉流,仅仅依靠我现有掌握的技术栈 ffmpeg + SDL,哎~有点难啊,我不知到 SDL 对于这样的一个界面是否支持,所以只能去看大名鼎鼎的 QT了,由于我一直没有时间去学习 QT,只能去找现成的项目,确实有,而且还算完善,这个项目本身的完成度是非常高的,对于一些码率较低的视频,处理起来是没有问题的,但是根本处理不了比如 wallpaper 上的动辄 80Mb/s 码率的视频,但是我想要的是它能够播放市面上所有的视频,而且是完美播放。

        嗯,首先,我将很多地方都改为采用硬件处理,比如视频解码,这些地方就是一些配置上的改动了,说复杂也还行,唯一需要注意的点就是:硬解码出来的原始帧数据,拷贝到 CPU 可访问的位置后,像素格式从 D3D11 --> NV12 了?额,不对,D3D11好像是GPU显存中的纹理格式,嗯···不重要,需要注意的时候再说,渲染的时候,需要注意 NV12 中的 Y\U\V 数据的存储形式 -- UV 混合存储,具体表现为 AVFrame->data[1] 中同时存放 UV 数据,并且是交错存放的,data[2] 中没有数据,和 YUV420P 不一样,注意一点就行;
        上述都仅仅是涉及到了读取、解码而已,渲染的工作又是一个关注的点:原项目中简单采用 QT 提供的CPU渲染方式,路径上全都是数据的 “深拷贝” ,最后通过 QImage 将帧数据给到渲染组件,浪费很大,我之前做的 SDL 播放器,直接通过 SDL 硬件渲染的方式,渲染到 SDL 创建的窗口上,所以我想用 ffmpeg + SDL + QT 来完成这样的一个 “想法”。
        在网上找了很多思路,最实用的就是在原有的 QMainWindow 窗口的基础上,嵌套一个 QWidget 窗口在原有的标签中,然后在这个 QWidget 上,添加 SDL 窗口,然后在他上面渲染就好,并且所有的对于该 ui 界面的操作,可以完全的交给 QT 来处理,SDL自己的窗口事件完全用不到,这样也好,用较少的改动,实现更高效的性能,嗯,就我现在的 QT 理解,也能够处理这些事情。

        遇到的问题:

        当然,在这个阶段其实遇到了很多问题,影响最深的就是:(1)现象:点击进度条,跳转到视频某一处后,然后再点击当前时刻之后的进度点进行跳转,画面直接卡在正在显示的一帧上,但是音频跳转是正常的,再次尝试,点击跳转时刻之后的进度点,有回复正常了,音视频依旧同步?(2)分析:既然恢复了正常,那么视频渲染和读取这条路径应该是没有异常退出,但是视频确实没有按照期望渲染出来?那么应该是 videoThread 卡在了某一个地方,卡在什么地方呢?分析代码,只有在执行同步逻辑时,才可能触发  SDL_Delay(10); 好吧,问题一定在这里,只有在视频时钟 > 音频时钟时,才会让视频线程阻塞,等待音频上来,好了,肯定是 seek 命令下发后,音视频的时间钟没有及时更新所导致的,那么再分析,video、audio的clock都有问题?audio在seek命令下发后,和期望渲染的音频一致,所以音频时钟没有问题,那么 video 的时钟应该是没有更新,导致 video_clock >> audio_clock,视频解码线程一直等待,所以才没有渲染,进行相应的修复后,正常如初。

        性能测试:播放测试集中的视频都不会卡顿并且音视频完全同步,CPU占用率在播放绝大多数视频时维持在1%~3%左右,只有在播放高码率视频时,才会出现10%左右的CPU占用率,只不过这依然比原项目动不动35%的占用率好多了,而且这个稳定;
        和b站的播放器作对比:b站本地播放器,无论播放测试集中的哪种视频,CPU占用率非常稳定,一直在1%~3%左右,不超过 3.5%,也就是不同码率的视频,对于该播放器而言,都一样,底层应该全都是 GPU 做的解码、渲染工作,CPU 累不到一点啊!
        未来要做的优化:(1)就像我前面处理推流端编码逻辑时,直接将 GPU 显存中的原样送给GPU进行硬编码,0拷贝,不过CPU,最后传给 CPU 的不过是一个编码后的帧,体积相对很小;
就根据这样的一个思路:最终SDL也是调用底层的渲染接口,给到 GPU的,那么在解码完成的那一刻,显存中是有这一帧的,我直接将它0拷贝(即使拷贝,也是GPU进行拷贝,比CPU快多了,走的路径也少)送给GPU渲染组件,这样子,肯定能节省大量的 CPU 资源;
        (2)或者说,不用(1)中这么底层的思路,QT中应该是有 OpenGL相关的功能模块的,等我系统性的学习完 QT 后,使用内置的这些组件进行渲染,肯定能够再次提高性能。
        

3. 开发工具与框架
  • FFmpeg 嗯,学习音视频方向肯定是要很熟悉这个工具,无论在何种场景下,只要是对音视频数据本身做操作,比如:编解码、滤镜处理···这把音视频界的 “瑞士军刀” 都发挥着非常大的作用。

        我学习ffmpeg,是从视频教程开始的,到现在复习也是一样的,因为视频教程付出的时间成较低,但是视频中讲解的其实仅仅停留在使用层面,至于你处理的音视频数据到底为什么这么处理?它的各种属性有什么作用?或者说,ffmpeg一些高级的功能,那些课程中,往往都不会深入,没有一定的音视频处理经验,理解不了,甚至于连最基本的照猫画虎都办不到,更别提深入理解了,所以根据视频教程学习了基本音视频的处理,就要去根据更深入的资源去深化对于 ffmpeg 本身的理解,这里推荐买一本 <<深入理解FFmpeg>>,下面是我的书:

        书里的内容讲得很好,尤其是调用 ffmpeg 进行硬解码那一章节,内部的代码和我之前参考的一个大佬的github项目非常非常相似,几乎一模一样,大佬估计是参与百年写这本书的人或者人家也会去研读这些东西。

        说到这里,我又又想起了一些事,请不要嫌我多嘴~

        刚上高中那会,我相信,每一个过来人,先不管自己的实力如何(或者说那时候,并没有认清现实),对于高考会有一个比较乐观的态度,具体表现为:诶~你说咱清北上不了,一个985还不是简简单单,然后高二,你说咱985够不着,211也还行,高二末,真正自己做过一套高考试题后,算了,这分数,一本线都没过?哎~原来我也只是个普通人,以后努努力,也上一个一本吧,你要说多努力吧,也没有,但是也没有摆烂,好像就平时的积累而言,考这样的一个分数,也是水到渠成的事,并不像一些人说得好像很累一样,还少对于大部分人而言,都是这样的一种状态。

        哎~做一件事,尤其是学习,我记得我当时听别人说 53 很出名,结果当时高一,就去买了,我尤其喜欢数学,我印象很深,那本书很薄,真的很薄,那天晚自习,是3个小时,从19-22点,挑战他,做了整整3个小时,我感觉从教室出来的那一刻,我真的脑袋都是轻飘飘的,我又是一个很犟的人,对于一些难题,我偏要在不借助解析的情况下,用自己的思路做出来,然后再去研读答案的思路,作对比,选择更优的解法,可惜啊,那是一道 4 星的题目,我看了半天,一点想法、思路都没有,就好像在看汉谟拉比法典,上面确实是有字的,但是脑子理解不了,因为什么呢?你不是那个时代的人,或者说你的积累、你的思考问题的角度、方式,和这个文字要求你的这些硬性条件,你一样都没有达到,不理解是必然的,但当时的我并不这么认为,我只是认为问题考察的太过刁钻,谁能那样思考啊?谁能?那个角度它凭什么认为我能够想到,真的,做数学题,很多时候就卡在这样的一个边缘,你能感觉到,触碰到那种感觉,你就能够做出来,那几乎是一种水到渠成的事,我以为靠积累就行,最后发现,根本不行,角度太多了,问题都不一样,哎~最后的结果是,那一面,是一面题,我死磕了整整一周,没做完,只有一道题是我自己做出来的,哎~从那之后,我几乎每节课上都不认真听讲,将时间全部投入到刷53中,那时候应该是魔怔了,哈哈,再去接触学校配套的资料时,发现那些题有难度吧,也有,很全面,但基本看一眼便知道思路了,也就懒得去写了,这件事很可怕,因为你可以因为资料的难度低就放弃他,转而去寻找更高难度,更能体现自己“价值”的哪种挑战性的东西,这种思想一旦养成,就会影响你的几乎对于整个学习的态度或者理解,我开始接触网上的教学视频而不再跟着学校走,这种影响平等的扩散到每一个科目中,哎~用一个词来说就是“眼高手低”,做那些题无非是累着自己,麻痹自己,以为自己正在努力地向着更高的方向前进,殊不知对于高考这样以中等题的为主的试卷,我只不过是在原地打转而已,把自己累着了,成绩倒是一点都没涨,哎~说笑了都,那个时候,真的对于这种行为是很享受的,游戏也好、娱乐也罢,如果没人陪我,我自己一个人绝对不会去做,我不认为那些有意思,我好像只喜欢沉浸在自己的世界里,那样会让人变得越来越孤僻,为什么被人评价为孤僻的这种人,天然的就被认为在行为上和正常人不一样?或者说和他们交流时,有些话是合理的,但总感觉从一个正常人的嘴里不应该出来?哎,其实我不想所说的那样,我只是喜欢那种氛围,我会因为某一件具体的、有趣的事情沉浸其中,但我并不讨厌外界的力量把我拉出去,我并不觉得这很冒犯,相反,我会觉得很开心,有人找我,所以我身边始终是有着这么一群朋友,和我交流,那么我和其他人对吧,交流起来也会是正常的,而如果我认为外界的声音、力量、人“打扰”到我了,那么我和群体之间的交流就会变少,到最后,如果一个更大的群体去看待我这个人,一定是“奇怪”的人,也就是孤僻,这并不是故意的,或者说心理有问题,并没有明显的恶意,只是和群体之间的交流变少了,慢慢地,就不再会交流了,嗯,说到哪儿了?

        偏了,我谈这段话想表明的意思是:“眼高手低”不可取,所谓什么培训机构啦、什么速成班啦、······这些凡是涉及到学习知识的东西,切不可眼高手低,知识是固定的,就在那,只看你愿不愿意学,愿不愿意踏踏实实的学,这个过程往往是枯燥且无味的,能坚持下来的人很少,向我这种自学的,更不用多说。在这里的 ffmpge 的学习,一定要讨踏踏实实的,不要认为学了那些了视频就搞懂了,即使是应付面试,也得要认真去学。

4. 未来学习方向
  • SRS项目学习
  • webrtc项目学习
  • 嵌入式音视频开发

        嗯···如果能够入行,带我理解更深一点再行讨论

5. 总结与个人感悟       
         上面讲述的经历是我自上来一直,愿能给你一些参考,就当成一片日记看看吧,也挺好,不是吗!
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐