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

【音视频连载-006】基础学习篇-SDL 播放 YUV 视频文件

公众号回复:OpenGL,领取学习资源大礼包

音视频学习入门技术文章连载:

  • 技术开发故事会连载

  • 【音视频连载-001】基础学习篇-SDL 介绍以及工程配置

  • 【音视频连载-002】基础学习篇-SDL 创建窗口并显示颜色

  • 【音视频连载-003】基础学习篇-SDL 消息循环和事件响应

  • 【音视频连载-004】基础学习篇-SDL 加载图片并显示

  • 【音视频连载-005】基础学习篇-SDL 加载 YUV 文件并显示

在前面的文章中,我们已经能够加载 YUV 帧并显示了,那是把一张图片转换成 YUV 帧得到的素材。

如果是一个 YUV 视频文件的话,那就是很多 YUV 帧连续在一起,既然能展示一帧,那肯定可以连续展示多帧。

接下来就要进行操作了。

YUV 视频文件素材

还是要准备一下 YUV 视频素材,不用网上到处去下载,用 FFmpeg 命令将 mp4 文件转换成 yuv 文件就好了。

ffmpeg -i file_name.mp4 filename.yuv

命令很简单,其中 file_name 是文件的名称,使用时记得替换。

由于生成的 yuv 文件是未经过压缩的,文件过大不方便传 Github ,所以在程序运行前要自己去生成一下文件。

同样,也可以用 ffplay 验证一下 yuv 文件转换是否正确。

ffplay -f rawvideo -video_size  100x100 yuv_filename.yuv

以上命令会打开一个窗口去播放视频内容,如果播放的和原来 mp4 文件内容一致,说明转换是成功的,YUV 文件可用。

代码实践

接下来就是代码实践环节,很多地方和前一篇文章加载 YUV 文件并显示 是类似的。

    // 打开文件 和 创建纹理 的代码和前一篇一样,不在放上来了
    if (texture != nullptr){
        SDL_Event windowEvent;
        while (true){
            if (SDL_PollEvent(&windowEvent)){
                if (SDL_QUIT == windowEvent.type){
                    break;
                }
            }
            // 读取内容
            if (fread(yuv_data,1,frameSize,pFile) != frameSize){
                // 读取内容小于 frameSize ,seek 到 0 ,重新读取,类似于重播
                fseek(pFile,0,SEEK_SET);
                fread(yuv_data,1,frameSize,pFile);
            }
            //
            SDL_UpdateTexture(texture, nullptr,yuv_data,width);
            SDL_RenderClear(renderer);
            SDL_RenderCopy(renderer,texture, nullptr, nullptr);
            SDL_RenderPresent(renderer);
        }
        SDL_DestroyWindow(window);
        SDL_Quit();
    }

打开文件和创建纹理代码内容和前面的一致,就不重新贴出来了。

YUV 内容转纹理以及渲染纹理上屏的操作也是一样的。

不同的是,读取 buffer 的操作放在了 while 里面。

如果对 SDL 的消息循环和事件响应还记得的话,就能明白每当 SDL_PollEvent 从消息队列中取出一个消息,只要不是退出事件,就会从 YUV 文件中读取 Buffer 并把它转成纹理渲染上屏。

如果读取的 Buffer 内容小于一帧 YUV 文件的大小,就会  Seek 到文件开头的位置,重新读取,类似于重播了。当然你也可以不重播,直接退出。

以下就是实际的运行效果:

以上的代码还是存在问题的,比如 YUV 视频播放的很快,比原来的 mp4 播放快多了。

这是因为播放的速率控制完全是根据 SDL_PollEvent 事件响应的速度来的,而不是根据 mp4 的帧率来播放。

可以通过自定义 SDL 事件,然后根据帧率控制自定义事件的发送速率,实现控制播放速度的目的。

另外,这里有很多参数都是事先知道的,比如视频宽高数据,在后面我们将通过 FFmpeg 来得到这些数据,实在真正的解码播放。

总结

以上就是音视频基础学习连载的 005 篇。

在实现加载 YUV 帧并显示的基础上,很容易就实现播放 YUV 视频文件了。

本文具体代码见仓库:

https://github.com/glumes/av-beginner

本篇文章对应的提交 tagav-beginner-004,可切换至对应源码查看。

能力有限,文中有不对之处,欢迎加我微信 ezglumes 进行交流~


技术交流,欢迎加我微信:ezglumes ,拉你入技术交流群。

扫码关注公众号【音视频开发进阶】,一起学习多媒体音视频开发~~~

喜欢就点个「在看」吧 ▽

相关文章:

  • Android 使用 OpenGL ES 绘制球面
  • 【音视频连载-007】基础学习篇-SDL 播放 PCM 音频文件(上)
  • PBO是OpenGL最高效的像素拷贝方式吗?
  • 游戏开发入门(一)游戏发展史
  • 【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下)
  • memcpy速度太慢?掌握这个技术让内存拷贝效率成倍提升
  • DXOMark是如何评价音频质量的
  • 【每周一记-001】~~~
  • 【音视频连载-009】第二季 FFmpeg 打造简易播放器
  • 【每周一记-002】
  • iOS中使用OpenGL 实现增高功能
  • 五分钟用C++11实现Android系统的Handler机制
  • 从入门到进阶|如何基于WebRTC搭建一个视频会议
  • 【音视频连载-010】第二季 FFmpeg 日志打印
  • 如何将ijkplayer引入AS工程中进行二次开发
  • bearychat的java client
  • Java小白进阶笔记(3)-初级面向对象
  • oldjun 检测网站的经验
  • Python学习笔记 字符串拼接
  • SpiderData 2019年2月13日 DApp数据排行榜
  • vue-router 实现分析
  • 从重复到重用
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 服务器从安装到部署全过程(二)
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 前嗅ForeSpider中数据浏览界面介绍
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 小试R空间处理新库sf
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​ssh免密码登录设置及问题总结
  • ​业务双活的数据切换思路设计(下)
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #QT(串口助手-界面)
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (1)bark-ml
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (三)elasticsearch 源码之启动流程分析
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)程序员疫苗:代码注入
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .net开发时的诡异问题,button的onclick事件无效
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .Net中间语言BeforeFieldInit
  • /var/log/cvslog 太大
  • @Autowired 与@Resource的区别
  • @在php中起什么作用?
  • [ 云计算 | AWS 实践 ] Java 如何重命名 Amazon S3 中的文件和文件夹
  • [AIGC codze] Kafka 的 rebalance 机制
  • [AIGC] 如何建立和优化你的工作流?
  • [Android实例] 保持屏幕长亮的两种方法 [转]
  • [Angular] 笔记 16:模板驱动表单 - 选择框与选项
  • [AutoSAR系列] 1.3 AutoSar 架构