利用FFmpeg和OpenGL ES 实现 3D 全景播放器

article/2025/8/22 5:18:14

前言

我们已经利用 FFmpeg + OpenGLES + OpenSLES 实现了一个多媒体播放器,本文将基于此播放器实现一个酷炫的 3D 全景播放器。

全景播放器原理

全景视频是由多台摄像机在一个位置同时向四面八方拍摄,最后经过后期拼接处理生成的。

用普通的多媒体播放器播放全景视频,画面会呈现出严重的拉伸和扭曲变形。

全景播放器将视频画面渲染到球面上,相当于从球心去观察内部球面,观察到的画面 360 度无死角,这也就是市面上大多数“ VR 盒子”的实现原理。

构建球面网格

全景播放器原理与普通播放器的本质区别在渲染图像部分,普通播放器只需将视频画面渲染到一个矩形平面上,而全景播放器需要将视频画面渲染到球面。

为实现全景播放器,我们只需要利用 OpenGL 构建一个球体,然后将 FFmpeg 解码的视频画面渲染到这个球体表面即可。

OpenGL ES 中所有 3D 物体均是由三角形构成的,构建一个球体只需要利用球坐标系中的经度角、维度角以及半径计算出球面点的三维坐标,最后这些坐标点构成一个个小矩形,每个矩形就可以分成 2 个三角形。

球坐标系

在球坐标系中,利用经度角、维度角和半径计算出球面点坐标公式如下:

x=rsinsβcosθ
y=rsinsθcosβ
z=rcosβ

根据上述公式计算球面顶点坐标的代码实现, 其中 ANGLE_SPAN 为步长,RADIUS 为半径,RADIAN 用于弧度转换 。

//构建顶点坐标
for (float vAngle = 90; vAngle > -90; vAngle = vAngle - ANGLE_SPAN) {//垂直方向每隔 ANGLE_SPAN 度计算一次for (float hAngle = 360; hAngle > 0; hAngle = hAngle - ANGLE_SPAN) {//水平方向每隔 ANGLE_SPAN 度计算一次double xozLength = RADIUS * cos(RADIAN(vAngle));float x1 = (float) (xozLength * cos(RADIAN(hAngle)));float z1 = (float) (xozLength * sin(RADIAN(hAngle)));float y1 = (float) (RADIUS * sin(RADIAN(vAngle)));xozLength = RADIUS * cos(RADIAN(vAngle - ANGLE_SPAN));float x2 = (float) (xozLength * cos(RADIAN(hAngle)));float z2 = (float) (xozLength * sin(RADIAN(hAngle)));float y2 = (float) (RADIUS * sin(RADIAN(vAngle - ANGLE_SPAN)));xozLength = RADIUS * cos(RADIAN(vAngle - ANGLE_SPAN));float x3 = (float) (xozLength * cos(RADIAN(hAngle - ANGLE_SPAN)));float z3 = (float) (xozLength * sin(RADIAN(hAngle - ANGLE_SPAN)));float y3 = (float) (RADIUS * sin(RADIAN(vAngle - ANGLE_SPAN)));xozLength = RADIUS * cos(RADIAN(vAngle));float x4 = (float) (xozLength * cos(RADIAN(hAngle - ANGLE_SPAN)));float z4 = (float) (xozLength * sin(RADIAN(hAngle - ANGLE_SPAN)));float y4 = (float) (RADIUS * sin(RADIAN(vAngle)));//球面小矩形的四个点vec3 v1(x1, y1, z1);vec3 v2(x2, y2, z2);vec3 v3(x3, y3, z3);vec3 v4(x4, y4, z4);//构建第一个三角形m_VertexCoords.push_back(v1);m_VertexCoords.push_back(v2);m_VertexCoords.push_back(v4);//构建第二个三角形m_VertexCoords.push_back(v4);m_VertexCoords.push_back(v2);m_VertexCoords.push_back(v3);}
}

计算对应球面坐标的纹理坐标,实际上就是计算固定行和列的网格点。

//构建纹理坐标,球面展开后的矩形
int width = 360 / ANGLE_SPAN;//列数
int height = 180 / ANGLE_SPAN;//行数
float dw = 1.0f / width;
float dh = 1.0f / height;
for (int i = 0; i < height; i++) {for (int j = 0; j < width; j++) {//每一个小矩形,由两个三角形构成,共六个点float s = j * dw;float t = i * dh;vec2 v1(s, t);vec2 v2(s, t + dh);vec2 v3(s + dw, t + dh);vec2 v4(s + dw, t);//构建第一个三角形m_TextureCoords.push_back(v1);m_TextureCoords.push_back(v2);m_TextureCoords.push_back(v4);//构建第二个三角形m_TextureCoords.push_back(v4);m_TextureCoords.push_back(v2);m_TextureCoords.push_back(v3);}
}

用 OpenGL 划线渲染球状网格,测试构建的球体是否准确。

渲染全景视频

计算好顶点坐标和纹理坐标后,剩下的就是简单的纹理映射(纹理贴图),不了解纹理映射的同学可以查看这篇文章纹理映射,篇幅有限,这里不展开讲述。

顶点坐标和纹理坐标初始化 VAO 。

// Generate VBO Ids and load the VBOs with data
glGenBuffers(2, m_VboIds);
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * m_VertexCoords.size(), &m_VertexCoords[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec2) * m_TextureCoords.size(), &m_TextureCoords[0], GL_STATIC_DRAW);// Generate VAO Id
glGenVertexArrays(1, &m_VaoId);
glBindVertexArray(m_VaoId);glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vec3), (const void *)0);
glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vec2), (const void *)0);
glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);glBindVertexArray(GL_NONE);

绘制视频画面。

// Use the program object
glUseProgram (m_ProgramObj);glBindVertexArray(m_VaoId);GLUtils::setMat4(m_ProgramObj, "u_MVPMatrix", m_MVPMatrix);//绑定纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
GLUtils::setFloat(m_ProgramObj, "s_TextureMap", 0);glDrawArrays(GL_TRIANGLES, 0, m_VertexCoords.size());

先绘制普通视频,看看是啥样儿。

最后绘制全景视频。

编译好的FFmpeg下载地址

FFmpeg_4.3.2支持Android的音视频处理库-Android文档类资源-CSDN文库

http://chatgpt.dhexx.cn/article/JbmQ3LlQ.shtml

相关文章

航空客运订票系统(C语言,软件用的DEV)

这两天整理之前的作业代码&#xff0c;把自己一点一点敲出来的系统又看了一下&#xff0c;挑几个发出来供大家参考。想要源码、报告可以找我啦&#xff0c;代码的注释之前写的都是非常详细的&#xff01; 但是不是无偿的啦&#xff08;不坑&#xff0c;一杯奶茶喽&#xff0c;不…

数据结构_航空客运订票系统(C实现)

文章目录 总述代码粗糙版修理版 还可以修正的点:余票不足时仍然提示还剩下几张(而不是直接拒绝该用户的订票操作)对于购票者的id 不单单是说约定一个可以不重复的主键(命名规则),而且还要辅以必要的检查违约功能 总述 在这里插入代码片 1&#xff0e; 问题描述&#xff1a;(题…

航空机票订票系统

项目介绍 主要功能是使订票系统可以录入航班情况&#xff0c;查询某个航线的情况、办理订票、办理退票、修改航班信息、查询订票信息等。完成此系统&#xff0c;需要综合运用数据结构课程中学到的几种典型数据结构&#xff0c;以及程序设计语言&#xff08;C语言&#xff09;&…

【数据结构应用】航空客运订票系统

目录 前言 一、作业要求介绍 二、各个函数的实现 1.头文件总结需要的功能 &#xff08;1&#xff09;结构体的定义 &#xff08;2&#xff09;各个功能的函数 2.各个函数的具体实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;打印航班信息表 &#xff08;4&…

Java实现航空机票订票系统

1、要求&#xff1a; &#xff08;1&#xff09;设计每条航线所涉及的信息&#xff0c;如终点站名、航班号、飞机号、飞机周日&#xff08;星期几&#xff09;、乘员定额、余票量、订定票的客户名单&#xff08;包括姓名、订票量、舱位等级1&#xff0c;2或3&#xff09;等&…

c语言航空订票系统程序设计,C语言航空订票系统

C语言航空订票系统 这 是 一 篇 用 C 语 言 编 写 的 航 空 订 票 系 统 的 论 文 。 该 系 统 使 用 的 是十 字 链 表 结 构 &#xff0c; 包 含 有 订 票 &#xff0c; 退 票 &#xff0c; 录 入 航 班 信 息 &#xff0c; 查 询 航 班 余 票 &#xff0c; 查询 个 人 订 票…

航空订票系统C++课程设计

航空订票系统 项目实践完整源码 前言一、功能演示二、代码总结 提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 编写程序模拟航空订票系统&#xff0c;要求实现以下功能&#xff1a; ① 允许增、删、改航班信息&#…

数据结构课设-航空客运订票系统(C语言实现)

航空客运订票系统&#xff08;C语言实现&#xff09; 系统框架已完成功能用户功能管理员功能其他 运行结果管理员添加航班客户订票添加候补客户退票 代码 系统框架 已完成功能 用户功能 查询航线&#xff1a;根据旅客提出的终点站名输出航班的信息。订票业务&#xff1a;根据…

C++课程设计:航空客运订票系统

航空客运订票系统 选题背景 方案论证 过程论述 运行结果 完整代码 选题背景 ①背景: 现在人们更多的使用飞机作为出行交通工具&#xff0c;因此机票票务市场也在快速发展。国内外航空事业在飞速发展&#xff0c;各航空公司对票务管理的要求也在不断的提高&#xff0c;对…

基于ssm的航空订票系统

基于ssm的航空订票系统 一、技术栈 ​ 前端 ​ vue全家桶、element-ui组件库、moment.js插件 ​ 后端 ​ springboot springmvc mybatis 二、功能描述 本系统是基于B/S架构的航空订票系统 系统分为三大用户–乘客、航空公司、后台管理员&#xff0c;本次课程设计主要实现…

课程设计之航空客运订票系统

/***************************************************** * 版权所有&#xff08;C&#xff09;2016&#xff0c;王力源 * *文件名称&#xff1a;A.C 航空售票系统 *文件标识&#xff1a;无 *内容摘要&#xff1a;航空售票系统 *其他说明&#xff1a;无 *当前版本&#xff1…

航空客运订票系统(数据结构课设)

前言&#xff1a; 广工数据结构课设&#xff0c;基本需求和选做内容以及一些小扩展均已实现&#xff0c;此博客仅展示一部分&#xff0c;实验报告文档、源代码和可运行程序&#xff08;.exe文件&#xff09;等可以去我的github或者码云上下载&#xff0c;如果对您有帮助&#…

python-数据结构-大学生-航空订票系统

python-数据结构-大学生-航空订票系统 1.问题描述及任务描述 1.1问题描述 航空订票系统&#xff1a;可以实现航空客运订票的主要业务活动 基本要求&#xff1a; &#xff08;1&#xff09;航线管理&#xff1a;每条航线所涉及的信息由&#xff1a;终点站名、航班号、飞机号、…

C语言航空订票系统课程设计

目录 1.设计目的&#xff1a; 2总体设计和功能&#xff1a; 3.菜单设计 4.各功能代码详解&#xff08;闲话少扯&#xff09;&#xff1a; 4.1.C语言文件的操作&#xff1a; 4.2.读取航班信息&#xff1a; C语言知识回顾 4.3.打印航班信息 5.根据要求查找航班&#xf…

C语言 数据结构课设 航空订票系统

目录 实现功能 部分功能测试截图 ​ 代码展示 实现功能 1.订票 2.退票 3.查询航班信息 4.修改航班信息 5.录入航班信息 6.打印订票信息 部分功能测试截图 功能选择界面 查询航班功能测试 订票功能测试 打印订票信息 代码展示 代码中需要的二个文件内容如下 第一个是代码中的…

【计算机毕业设计】41.航空订票系统

摘 要 网络的广泛应用给生活带来了十分的便利。所以把航空订票与现在网络相结合&#xff0c;利用JSP技术建设航空订票系统&#xff0c;实现航空订票的信息化。则对于进一步提高航班公司的发展&#xff0c;丰富航空订票经验能起到不少的促进作用。 航空订票系统能够通过互联网…

航空订票系统(javaweb项目)

航空订票系统课程设计 一、项目选题 航空订票系统 二、项目背景 当今社会知识经济高速发展&#xff0c;信息化在各个行业内正在被越来越广泛的应用。人们生活水平的不断提高&#xff0c;使得出行的交通工具也跟着发展起来。如今乘飞机出行的人越来越多&#xff0c;这方面的市…

数据结构课设——航空航天订票系统

文章目录 一、系统简介    1、业务活动    2、操作和功能二、系统功能模块图    1、系统功能模块图    2、函数功能模块三、详细描述    1、数据结构    2、设计思路四、运行结果    1、查询所有航班    2、根据起点终点搜索航班    3、订…

mysql导出表结构及数据的三种方法

navicat导出表一共有三中用法&#xff1a; 第一种&#xff1a;数据库上右键—>"转储SQL文件"&#xff0c;如图&#xff1a; "转储文件"是把整个数据库表全部导出&#xff0c;所有的表都是先drop然后create&#xff0c;insert。 第二种&#xff1a;部分表…

将mysql中的数据库表导出和导入

目录 导出数据库 导入数据库 导出数据库 如果你的mysql没有配置环境变量&#xff0c;首先需要进到你所安装的mysql目录下的bin目录 进入之后输入&#xff1a; mysqldump -uroot -p booksystem > booksystem.sql 其中booksystem是你要导出的数据库中的名字&#xff0c;book…