2024-06-18 22:56:24
在 Mac M1 等系列芯片编译和开发 WebRTC-Android 库 中介绍了如何编译 WebRTC-Android 库,分别是编译动态库 so
和 AAR
,对应着在 Android 开发中也有不同的接入方式。
2024-04-27 14:21:37
众所周知,编译 WebRTC-Android 库是需要在 Linux 系统上的,这是由于源码里编译脚本限制导致。
当然也可以在 Mac 平台上进行编译,不过就需要对源码进行魔改了,毕竟拉取的是 Linux 下的源码和相关配置,要把这些配置替换成 Mac 平台上的,比如 Linux 下的 C++ 编译配置、Android NDK 配置等,这种方式侵入性比较大,而且还相当折腾,费时费力。
2024-04-21 20:00:40
就在前不久,Meta 正式发布了最新版本的开源大模型 Llama3 ,是**迄今为止能力最强的开源大模型。
2024-03-29 22:13:47
最近项目中遇到一个问题,用户上传一个 H.265 编码,并且是 Open-GOP 格式的某个视频。
该视频在 iOS 平台上用 AssetReader 进行解码,频繁 Seek 的场景下会出现卡死。
2024-02-01 16:53:35
初识 Flutter 的 Demo 是一个点击按键然后数字增加的小应用,这小应用就涉及到了 Flutter 中的状态管理,核心就是 setState
方法。
2023-05-24 19:27:46
ChatGPT 技术最近有多火就不用再介绍了吧,连超级大佬都说了 ChatGPT 这是几百年不遇的、类似发明电的工业革命一样的机遇。
这种机遇当然不能错过,使用得当那就像玄幻小说里的男主角开了挂一样,用来做快速查询、资料搜集、辅助学习相当不错,前提是用对了提示词关键字,难怪吴恩达都开了一门课程讲如何构造 Prompt 。
接下来就由 ChatGPT 提供一下技术干货,我问了几个关键字,这是它的解答,各位看官评判一下回答的可还行?
2023-01-07 11:36:43
2022-12-27 22:24:27
基于 UE 4.27 的版本添加自定义的 ShadingModel ,大致分为两步:
1. 在 UE Editor 中添加自定义的 ShadingModel 入口。这样在创建材质时可以选择对应的 ShadingModel 。
2. 在 Shader 中对自定义的 ShadingModel 做渲染上的处理。比如自定义的 BxDF 函数,以及对光照的特殊处理等。
2022-11-05 14:56:53
最近在学习 UE 相关的使用,正好看到一篇文章讲解用 Control Rig 实现简单捏脸功能,这种小而美的完整案例挺适合来练手的,涉及到了 UI、蓝图、动画、骨骼等方面,值得推荐一下。
2022-09-12 11:58:15
UE 中提供了 凹凸贴图偏移
的贴图来实现修改 UV 坐标达到提升表面细节,使材质产生深度错觉。凹凸贴图偏移是 UE4 中的术语,其实就对应于 LearnOpenGL 网站上的 视差贴图
。
2022-06-18 13:08:36
在知识星球里面,有一个同学咨询纹理池是如何实现的。
关于纹理池的实现方案以及背后的原因、细节、技巧,只有长篇大论才足以论道,本文暂表不提。
针对问题本身,笔者发现这位同学对OpenGL中的共享资源存在误解,他认为OpenGL中可以共享FBO。
为了纠正错误,也为了让大家在使用OpenGL之前理清一些基本概念,笔者专门附上一篇旧文系统讲述上下文的创建及共享。
2022-06-18 13:02:00
在之前文章中已经介绍过了 MP4 标准的来源以及它的格式定义,基本上就是由一个个 Box 组成的,大致的结构如下:
ftyp
moov
mvhd
trak
tkhd
mdia
trak
tkhd
mdia
mdat
接下来我们就要去手动解析 MP4 文件,注意这可不是用 FFmpeg 来解封装,而是从 MP4 文件中一个一个字节读取信息并解析它的含义获得想要的内容。
2022-05-05 21:39:07
之前介绍了在 Windows 上查看 MP4 格式信息,使用的是 Mp4 Explorer 软件,具体使用如下:
005 | 播放器系列专栏-在 Windows 上查看 MP4 格式
现在该介绍一下 MAC 上用的软件了,它就是 MediaInfo 软件,官网地址如下:
2022-04-17 22:06:45
在知识星球中有位同学咨询了关于直播、webrtc、FFmpeg的一系列问题,这些问题都是大家平时关注的问题。
为了让大家在从事音视频之前能对相关概念有一个清晰的理解,此前对这些问题做了系统性的回复,这些答案也许会对你有所帮助,也算是抛砖引玉,欢迎大家一起交流。
2022-04-16 18:29:38
在之前的文章中我们已经认识了 MP4 视频,知道了它是音频和视频的容器,并且由一系列 Box 组成。
在前文的附件中,我们也给出了对应的资料,包括 MP4 格式的官方定义以及各种 Box 类型的描述。
但是纸上得来终觉浅,绝知此事要躬行,光是理论上知道了还不行,需要亲自实践加深印象。
这次会在 Windows 平台上用工具解析查看 MP4 格式信息,推荐的工具就是 Mp4 Explorer。
2022-04-10 22:49:38
在知识星球里面有位 PM 同学,咨询关于音视频里面的解码帧率和渲染帧率,关于这两个概念其实挺绕的,不同的人可能还有不同的看法,所以也让大家一起来评估一下解读是否正确!!
2022-03-18 21:07:14
众所周知,前段时间开通了知识星球,旨在为音视频的开发和学习提供更专业的问答氛围。
同时也考虑在星球内出一些干货教程,回馈大家的信任,一番思索之后,决定在星球内出一个播放器的项目实践。
2022-03-08 10:24:25
目前流媒体开发工程师工作内容主要是在做什么?
这是来自知识星球一位朋友的提问,非常好的一个问题,也是很多想要进入音视频领域的粉丝朋友们想要了解的。
在知识星球内回答了一下,正好也放出来供大家参考一下。
有想要加入知识星球的朋友,可以通过如下链接了解一下:
2022-01-18 00:16:16
周末时候看到一篇推送说 FFmpeg 升级到 5.0 版本了。
其中提到 FFmpeg 引入了 Vulkan 驱动的新滤镜,用于视频水平、垂直翻转。
看到 FFmpeg 引入了 Vulkan ,想着这是要有什么大动作啊,直接利好 Vulkan 嘛?
后来又仔细看了下 FFmpeg 的 Changelog ,原来早在 4.3 版本就已经开始支持 Vulkan 了。
2021-12-19 17:37:37
周末在家折腾 Windows 平台下 FFmepg 和 LibX264 库的编译,长期以来都是在 Mac 平台下做开发,切换到 Windows 平台下还是踩了不少坑。
2021-11-28 22:06:37
前两天在群里面看到大佬转发一篇文章:Getting started with Metal-cpp 。
链接在此:
文章大意就是:一顿操作安排上,苹果现在支持用 C++ 开发 Metal 了。
2021-11-26 12:47:46
最近有不少朋友加我微信或者在技术群里面咨询:想要转行音视频岗位要怎么做?
俗话说:隔行如隔山。从一个岗位转向另一个岗位,肯定不是三言两语就能说清楚的。
和多数人一样,我之前是从事 Android 客户端开发,后来跳槽到头条做音视频 SDK 开发,参与了抖音和剪映这样的短视频项目,编程语言也从 Java 转向了 C++,技术栈也对应发生了变化。正因如此,也算是完成了一次职业转型,再出去找工作的话,肯定会更偏向音视频底层的开发,而不再是应用层的岗位了。
相对来说,这样的经历对想从事音视频行业的朋友会比较具有参考性,我也很乐意和大家分享这里面的故事,之前还在 B 站上做了一次直播活动,没有参加的朋友可以观看下面的录播内容:
视频地址如下:
2021-11-07 10:58:20
昨天周六,群里面还有人在技术交流!!。
默默吐槽一下:这些人真卷啊,大周末还搞技术,是游戏不好玩还是电影不好看。
2021-10-29 22:16:39
前几天发了一篇 FFmpeg 调用 Android MediaCodec 进行硬解码 的文章,这里面的技术点不算太难,也还是调用 FFmpeg 的常用接口操作,但重点在于 FFmpeg 的版本选择以及编译选项要开启 MediaCodec 才行。
关于 FFmpeg 的编译,是个老生常谈的话题了,很多初学者都会卡在怎么编译动态库 so 的问题上,这其实也是 Android 开发转音视频的一大拦路虎,一行 FFmpeg 代码都没来得及写呢,就得先折腾好久编译问题。
2021-10-19 10:18:38
文章原创首发公众号:音视频开发进阶。链接地址:https://mp.weixin.qq.com/s/S8NwQnY4uyQulfZnRF7t_A
FFmpeg 在 3.1 版本之后支持调用平台硬件进行解码,也就是说可以通过 FFmpeg 的 C 代码去调用 Android 上的 MediaCodec 了。
2021-09-02 10:49:02
用 WebRTC 创建相机预览,不到 50 行核心代码就可以轻松搞定了。
直接使用官方给的版本就好了,不需要再去额外编译。
implementation 'org.webrtc:google-webrtc:1.0.30039'
后面都会使用该版本做测试的。
2021-09-02 10:45:56
Half Lambert 模型(也叫作半兰伯特模型)在 Lambert 模型的基础之上做了一些优化。
在 Lambert 模型中,光照无法到达的区域,比如模型的背面,模型外观通常是全黑的,没有任何明暗变化,而 Half Lambert 模型就是改善这一状况。
回顾 Lambert 模型的计算公式如下:
$c_{diffuse} = (c_{light} \cdot m_{diffuse}) \cdot max (0,n \cdot I)$
2021-09-02 10:45:46
在标准光照模型中,可以把光照分为四种:
用一张图来表示各个光照:
而 Lambert 光照模型主要是处理物体漫反射的。
2021-09-02 10:44:03
光照可以说是整个计算机图形学里面最重要的部分了,当展现物体时如何模拟真实世界中的光照环境,这往往是很复杂的。
由于光是可以散射的,一个物体不仅仅可以接收来自直接光源的照射,还可以接收来自周围环境的散射光,而在渲染时,要计算周围环境的散射光就无疑加大了计算量,因为周围环境远比光源复杂多了。
下面就是一张很逼真的光照渲染实例:
如果说这是用手机拍的照片,可能我都分不出来哪里有问题,而计算机模拟真实感渲染就是追求这一目标吧。
2021-08-23 13:04:19
用 Unity 去显示一张图片纹理比用 OpenGL 代码去显示图片要简单多了,而这正是因为 Unity 在背后做了很多封装工作。
要显示的图片如下所示:
它的分辨率是 2560x1600 ,也就是矩形图片,并非正方形。
2021-08-15 15:18:06
Unity 中的 Shader 不同于 OpenGL 的 GLSL ,它是通过 ShaderLab 语言编写的。
ShaderLab 是 Unity 为开发者提供的高层级的渲染抽象层,它是一种说明性语言。
2021-02-20 21:04:42
在使用模板时可以显示指定模板类型,尤其是针对有返回类型的模板,显示指定可以避免类型转换带来的困扰。
但有时候显示指定模板实参类型会给用户增添额外负担,而且不会带来什么好处。
比如如下代码,接受表示序列的一对迭代器和返回序列中的一个元素的引用:
template<typename It>
??? &fcn(It beg,It end){
return *beg;
}
我们并不知道返回结果的准确类型,但知道所需类型是所处理的序列的元素类型。
vector<int> vi = {1,2,3,4,5};
auto &i =fcn(vi.begin,vi.end());
如上代码,知道函数应该返回 *beg,而且知道我们可以用 decltype(*beg) 来获取此表达式的类型。
但是,在编译器遇到函数的参数列表之前,beg 都是不存在的。为此,我们需要使用尾置返回类型。
2021-02-20 21:03:04
C++11 中引入了可变参数模板的特性,可变参数模板就是一个接受可变数目参数的模板函数或者模板类。
可变数目的参数被称为参数包,存在如下两种参数包:
具体如下所示,声明了一个可变参数函数模板。
// Args 是一个模板参数包;rest 是一个函数参数包
// Args 表示零个或多个模板类型参数
// rest 表示零个或多个函数参数
template <typename T,typename... Args>
void foo(const T &t, const Args&... rest);
2021-02-09 16:38:48
C++ 11 引入了 std::thread 标准库,方便了多线程相关的开发工作。
说到多线程开发,可不仅仅是创建一个新线程就好了,不可避免的要涉及到线程同步的问题。
而保证线程同步,实现线程安全,就要用到相关的工具了,比如信号量、互斥量、条件变量、原子变量等等。
这些名词概念都是来操作系统里面引申来的,并不是属于哪一种编程语言所特有的,在不同语言上的表现形式不一样,但其背后的原理是一致的。
C++ 11 同样引入了 mutex、condition_variable、future 等实现线程安全的类,下面就来一一了解它们。
2021-02-09 12:11:34
在前面的文章中,模板参数除了是类型之外,还可以是非类型参数,但只有整型和指向外部链接对象的指针才可以。
除此之外,模板类型同样可以作为类型参数,并且还很有用处。
2021-02-09 12:11:01
在之前的类模板中,只在类声明时用了 typename 指定模板参数类型,之后的成员函数复用模板参数类型。
但实际上,类成员也可以是模板,嵌套类和成员函数都可以作为模板。
2021-02-09 10:19:51
在之前的代码示例中,频繁用到 typename
关键字。
它的作用就是声明模板参数是类型参数(对于非类型参数,之前的文章也有提到了),也可以用 class
关键字来代替,但为了避免歧义,大多还是使用 typename
了。
除此之外,在模板的定义也可以使用 typename
关键字,用来指定变量的类型。
2021-02-08 20:14:18
前面已经介绍了函数模板和类模板,还介绍了类模板的默认参数,在代码示例中都是用具体类型来作为模板参数的。
实际上,模板参数不局限于类型,普通值也可以作为模板参数,也就是本篇要讲的内容:非类型模板参数。
2021-02-08 17:57:04
现如今,掌握 C++ 模板技巧并且熟练使用可以说是能力进阶的必备内容了。
在一些优秀的开源项目中经常能看到模板的使用,要是不了解其使用方法,对分析源码都会有些阻碍。
推荐阅读《C++ Templates 中文版》一书,或许可以让你对 C++ 模板有个更加系统的概念,同时辅助阅读网上相关的博客文章加深理解,在代码实践中去掌握提高。
C++ 模板主要可以分为函数模板和类模板,这次就是介绍它们两个。
2021-01-11 09:54:15
众所周知,Swift 是不能直接调用 C/C++ 代码的,而 Objective-C 是可以直接调用的。
想要 Swift 调用 C++ 方法,需要走 Objective-C 中转才行,类似于 Java 调用 C++ 代码需要走 JNI 一样。
反而 Swift 调用 C 方法还要简单一些,不需要 Objective-C 中转,以下就是具体操作详情~
2021-01-06 19:44:28
2021 年的第一次公众号文章推送,它会迟到,但绝不缺席!!
2020 年已经成为过去,新的一年又该有新的规划了,沉思良久之后决定就是它啦~~
今年的发力点就是从零打造渲染引擎。
2020-11-17 00:22:12
最近在捣鼓 iOS 上的音视频开发,由于之前并没有 iOS 开发经验,直接上手写代码的话压力还是挺大的,因此也趁机看了下 iOS 开发的内容,算是做一些准备工作吧。
2020-08-10 21:01:28
最近开始折腾 WebRTC 了。
先介绍一下 WebRTC 源码编译以及 Android 开发环境的搭建。
整个下载编译过程都需要能够正常访问外网,这需要自己想办法克服了。
2020-08-03 20:22:39
前段时间博客网站一直无法访问,还有不少朋友特意发微信告诉我,感谢大家的好意了!
网站是:https://glumes.com
其实是博客域名在备案啦。
之前博客搭建用的是 Github Pages 方案,访问速度一直被人诟病。
上个月就决定把服务器换成阿里云了,访问速度如火箭般提升🚀🚀🚀~~
2020-05-22 14:33:35
避免图片丢失,建议阅读微信原文:
前几天发布了这样一篇文章:
除了介绍 KodeLife 的使用之外,还附带了一个 Shader 绘制网格效果的代码。
把这篇文章发到技术群里,随机就有大佬指出不足之处,提示说代码还可以进一步优化,并且提供了源码学习。
可见加入一个高质量的技术群是多么重要,哪怕平时不说话,围观大佬们聊天都能学到很多。
现在加入还来得及,尚有余位,详情点击如下链接:
2020-05-18 11:39:56
避免图片丢失,建议阅读微信原文:
经常有朋友在群里面问想学习 Shader 有什么工具可以推荐?
今天它来了~~~
推荐一款强大的 Shader 实时编辑预览的工具 —— KodeLife
。
对,它的名字就叫做 KodeLife
,可别看成 KobeLife
了,一个字母之差完全就是两个概念。
KodeLife
的官网地址如下:
贴一张主页封面图:
有需要的同学可以去官网下载安装,它是需要购买 License 的,不过可以免费使用两个月。
2020-05-18 11:37:09
本篇文章主要是讲解如何通过 FFmpeg 代码来获取文件信息。
首先准备一个文件,用命令行来查看它的基本信息。
文件地址如下:
https://github.com/glumes/av-beginner/blob/master/resource/video/video-avi-320x320.avi
这个文件很有意思,它的内容是一个时钟,每隔一秒,秒针都会跳动,同时还会发出滴答的声音,很方便后续做音视频同步处理。
2020-05-06 23:10:48
避免图片丢失,建议阅读微信原文:
在 直播 中有提到几个不错的开源项目,这里再重点推荐一下:
目前,市面上关于音视频学习的相关书籍并不多,而且即使看了书籍学了理论,最终还是要回归到代码上来。
毕竟 IT 行业实践性要求高,强调动手能力,音视频这方面就更得多操作和探索了。
推荐下面几个项目会各有侧重,分别涵盖了 Android 音视频录制 API 、OpenGL 渲染和综合运用的例子。
2020-04-27 23:37:03
音视频连载系列已经停更一段时间,再这么停下去估计就要掉粉了,捡起来继续更新~~~
接下来主要是讲解 FFmpeg 相关的内容,比如这篇就从简单的日志打印开始说起。
2020-03-22 18:38:09
接上篇 SDL 播放 PCM 音频文件,已经实现了 推
的模式去播放,接下来看看 拉
的模式如何实现。
2020-03-16 09:47:30
在前面的文章中已经能够利用 SDL 去播放 YUV 视频文件了,接下来要通过 SDL 去播放 PCM 音频文件。
SDL 播放音频文件有两种方法,可以理解成 推(push)
和拉(pull)
两种模式。
推
就是我们主动向设备缓冲区填充 Buffer ,而 拉
就是由设备拉取 Buffer 填充到缓冲区。
在一些开发模型中,如果数据传递能够抽象成流
的形式,那么肯定就会有推
和拉
两种模式。
本篇文章主要是讲解 SDL 以推的形式播放音频文件。
2020-03-15 18:38:03
在前面的文章中,我们已经能够加载 YUV 帧并显示了,那是把一张图片转换成 YUV 帧得到的素材。
如果是一个 YUV 视频文件的话,那就是很多 YUV 帧连续在一起,既然能展示一帧,那肯定可以连续展示多帧。
接下来就要这样的操作。
2020-03-08 21:44:09
在前面的文章中已经介绍完 SDL 显示窗口、消息循环和事件响应这些基础内容,有了这些基础就可以进行功能性开发了。
本篇的主要内容是利用 SDL 加载并显示一张图片,然后再去进行更多的音视频操作。
2020-03-03 22:54:26
在前面的文章中已经创建了一个 SDL 窗口并且显示指定的颜色。
为了让窗口显示出来,在程序中写了一个死循环,这几行代码就是 SDL 消息循环和事件响应的核心缩影了。
SDL_Event windowEvent;
while (true){
if (SDL_PollEvent(&windowEvent)){
if (SDL_QUIT == windowEvent.type){
break;
}
}
}
2020-03-02 20:40:02
在前面的文章中我们已经完成了 SDL 的工程配置,接下来就是 SDL 相关功能的开发。
本篇文章主要是创建一个应用程序窗口并显示。
2020-02-26 23:33:35
这是音视频基础学习系列的第一篇文章,主要讲解 SDL 是什么以及为什么要用到它,看似和音视频没啥卵关系,其实必不可少。
2020-01-04 22:53:52
避免图片丢失,建议阅读微信原文:
学习 OpenGL ,相信肯定有不少人看过这个网站:
这是它的英文原版网站,后来又有了不同语言的翻译版本,对应中文就是:
这两个网站对于学习 OpenGL 帮助非常大,既可以用作入门的教材,也可以作为工具书,后续进行查漏补缺。
并且它的内容很全面,除了 OpenGL 基础知识、坐标系统、纹理、Shader、模型加载等,还有高级光照、PBR 等渲染技巧,这些在渲染引擎的开发中都是会用到的,后面会继续和大家分享。
2019-12-27 15:40:54
时光荏苒,岁月如梭。
又到了回顾过去,展望未来的(chui)高(niu)光(bi)时刻了~~
去年年底准备跑路,然后年前面试,拿了头条的 offer,年后就入职了~~~
应聘的岗位是 Android-多媒体开发工程师,具体招聘岗位见官网:多媒体平台研发工程师-Android — 抖音火山
工作内容简单说就是做音视频 SDK,支持头条的一些业务。
2019-12-27 10:58:55
前段时间在慕课网上体验了一把做讲师的感觉,录制了一套免费技术视频~~
如下图所示:
在慕课网上通过如下路径就可以找到啦
免费课程 -> 课程 -> 移动开发 -> Android -> Android CMake 以及 NDK 实践基础
2019-10-20 22:49:00
避免图片丢失,建议阅读微信原文:
转场效果是什么?
转场效果,简单来说就是两段视频之间的衔接过渡效果。
现在拍摄 vlog 的玩家越来越多,要是视频没有一两个炫酷的转场效果,都不好意思拿出来炫酷了。
那么如何在视频编辑软件中实现转场效果呢?
这里提供使用 OpenGL 实现视频转场的一个小示例,我们可以通过自定义 GLSL 来实现不同的转场效果。
以在 Android 平台上作为演示,但其实不管是 Android 还是 iOS,实现的原理都是一样的。
首先要有两段视频,视频 A 和视频 B,先播放视频 A 后播放视频 B,中间有一段过程称为 C ,C 就是视频 A、B 做转场动画的时间段。
如下所示:
播放器按照时间顺序,从 A -> C -> B 的播放,这样就有了转场的效果。
2019-08-20 23:51:59
避免图片丢失,建议阅读微信原文:
说到贝塞尔曲线,大家肯定都不陌生,网上有很多关于介绍和理解贝塞尔曲线的优秀文章和动态图。
以下两个是比较经典的动图了。
二阶贝塞尔曲线:
三阶贝塞尔曲线:
由于在工作中经常要和贝塞尔曲线打交道,所以简单说一下自己的理解:
2019-07-13 00:08:18
2019-07-12 23:26:58
在之前的文章中介绍了 stb_image
图像库,还顺带提到了 libpng 和 libjpeg ,这篇文章就是介绍如何在 Android 平台上用 CMake 编译 libpng 动态库以及 libpng 使用实践。
2019-05-19 23:25:31
最近关注了一波 rust,一门目前还比较小众但却很强大的编程语言,官网地址如下:
rust 的学习曲线比较陡峭,在开始学习之前建议看看王垠的这篇文章 《如何掌握所有的编程语言》,地址如下:
学习语言,重要的是掌握其语言特性。
王垠举了一些语言特性的例子:
看着这些特性是不是很像一些编程语言书的目录🤔
在学习 rust 的时候也可以照着这些语言特性去对比自己是否掌握了。
2019-05-14 23:16:45
在 OpenGL 开发中,我们要渲染一张图片,通常先是得到一张图片对应的 Bitmap ,然后将该 Bitmap 作为纹理上传到 OpenGL 中。在 Android 中有封装好的 GLUtils
类的 texImage2D
方法供我们调用。
public static void texImage2D(int target, int level, int internalformat,
Bitmap bitmap, int type, int border)
该方法的底层原理实际上也是解析了该 Bitmap ,得到了 Bitmap 所有的像素数据,类似于 Android NDK 关于 Bitmap 操作的 AndroidBitmap_lockPixels
方法,如果你不太了解该方法,可以参考这篇文章:Android JNI 之 Bitmap 操作。
得到了所有像素数据之后,实际最终还是调用了 OpenGL 的 glTexImage2D
来实现纹理上传。当然,如果可以直接得到所有数据,也不需要走解析 Bitmap 这一步了,这种场景最常见的就是把相机作为输入了。
2019-05-12 21:57:07
避免图片丢失,建议阅读微信原文:
说到图像解码库,最容易想起的就是 libpng
和 libjpeg
这两个老牌图像解码库了。
libpng
和 libjpeg
分别各自对应 png
和 jpeg
两种图像格式。这两种格式的区别如下:
png
支持透明度,无损压缩的图片格式,能在保证不失真的情况下尽可能压缩图像文件的大小,因此图像质量高,在一些贴纸应用中也大部分用的是 png 图片。
jpg
不支持透明度,有损压缩的图片格式,有损压缩会使得原始图片数据质量下载,也因此它占用的内存小,在网页应用中加速速度快。
要想在工程中同时解码 png
和 jpeg
格式图片,就必须同时引用这两种库,而且还得经过一系列编译步骤才行。
在这里,介绍一个简单易用的图像库:stb_image
。Github 地址为:https://github.com/nothings/stb ,目前已经有了 9600+ Star 。它的使用非常简单,看看 README 可能你就会了。
2019-05-02 21:21:40
微博图床一时爽,迁移火葬场
前几天在群里看到说新浪微博图床挂掉了,图床上的图片链接单独访问还可以,但是在博客文章上就显示不出来了。
去自己网站上看一下,果然,连博客首页图片都加载不出来了,极大地影响了阅读体验呀。
还好图片链接是可以访问的,这就意味着图片还在,还来得及做迁移和备份。
回顾之前用了好多免(hao)费(yang)图(mao)床,从最早的 七牛,到 Cloudinary,再到 微博图床。七牛由于是临时域名,没有及时备份图片,导致图都没了,而 Cloudinary 和 微博图床 倒还是可以继续访问的。不过这种薅羊毛总不是个办法,万一服务商政策变了,又得再迁移图片了。
果然,免费的才是最贵的。
2019-04-07 15:39:14
在之前的文章中,讲到了 Command-Buffer
提交给 Queue
去执行,也提到了 Vulkan 实现跨平台机制,是有一些拓展的,这里就讲讲 Vulkan 窗口系统的拓展(Vulkan Window System Integration WSI),如下图所示:
2019-01-09 09:50:20
此篇文章继续学习 Vulkan 中的组件:Command-Buffer 。
2019-01-07 11:03:18
在 Vulkan 的系列文章中出现过如下的图片:
这张图片很详细的概括了 Vulkan 中的重要组件以及它们的工作流程,接下来的文章中会针对每个组件进行学习讲解并配上相关的示例代码,首先是 Instance、Device 和 Queue 组件。
2018-11-19 15:58:17
在 Java 5.0 之前,在协调对共享对象的访问时可以使用的机制只有 synchronized
内置锁和 volatile
关键字。
Java 5.0 增加了一种新的机制:Lock
显式锁,当内置锁 synchronized
不适用时,它就可以作为一种新的选择。
回顾一下内置锁 synchronized 的使用:
// synchronized关键字用法示例
public synchronized void add(int t){// 同步方法
this.v += t;
}
public static synchronized void sub(int t){// 同步静态方法
value -= t;
}
public int decrementAndGet(){
synchronized(obj){// 同步代码块
return --v;
}
}
内置锁不需要显式的获取和释放,任何一个对象都能作为一把内置锁。
2018-09-19 23:39:28
避免图片丢失,建议阅读微信原文:
在 Android 4.1 版本提供了 MediaCodec 接口来访问设备的编解码器,不同于 FFmpeg 的软件编解码,它采用的是硬件编解码能力,因此在速度上会比软解更具有优势,但是由于 Android 的碎片化问题,机型众多,版本各异,导致 MediaCodec 在机型兼容性上需要花精力去适配,并且编解码流程不可控,全交由厂商的底层硬件去实现,最终得到的视频质量不一定很理想。
虽然 MediaCodec 仍然存在一定的弊端,但是对于快速实现编解码需求,还是很值得参考的。
以将相机预览的 YUV 数据编码成 H264 视频流为例来解析 MediaCodec 的使用。
2018-09-12 09:19:09
Android Studio 从 2.2 版本起开始支持 CMake ,可以通过 CMake 和 NDK 将 C/C++ 代码编译成底层的库,然后再配合 Gradle 的编译将库打包到 APK 中。
这意味就不需要再编写 .mk
文件来编译 so
动态库了。
2018-09-09 15:20:42
在之前的文章中, 主要介绍了 OpenGL ES 2.0 的 GLSL 语法,在 OpenGL ES 3.0 中语法又有了一些变化。
本文的内容来自于《OpenGL ES 3.x 游戏开发 上卷》。
2018-09-09 15:07:20
要想发挥 OpenGL ES 自定义渲染管线的功能,就得学会写 GLSL 着色器脚本。
本文中的内容来自于 《Android 3D 游戏开发技术宝典 OpenGL ES 2.0》。
2018-09-04 22:28:11
避免图片丢失,建议阅读微信原文:
帧缓冲(Framebuffer Object),简称 FBO
,在渲染绘制中, 图像最终都是绘制到 FBO 上的,一般都是默认的 FBO 上,也就是我们的屏幕。
除此之外,还可以创建自己的 FBO,用来作为绘制的载体,当在自己的 FBO 上绘制好了之后,可以再把绘制内容显示到屏幕上,实现一个双缓冲的绘制。
FBO 实际上是由颜色附件、深度附件、模板附件组成的,作为着色器各方面(一般包括颜色、深度、深度值)绘制结果存储的逻辑对象。
2018-09-02 21:26:55
避免图片丢失,建议阅读微信原文:
OpenGL 是跨平台的、专业的图形编程接口,而接口的实现是由厂商来完成的。
而当我们使用这组接口完成绘制之后,要把结果显示在屏幕上,就要用到 EGL
来完成这个转换工作。
2018-09-02 21:14:09
避免图片丢失,建议阅读微信原文:
GPUImage 是 iOS 上一个基于 OpenGL 进行图像处理的开源框架,后来有人借鉴它的想法实现了一个 Android 版本的 GPUImage ,本文也主要对 Android 版本的 GPUImage 进行分析。
2018-08-28 22:55:49
代理模式的使用场景如下:
当无法或不想直接访问某个对象或访问对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
2018-07-26 12:47:49
在 OpenGL 的世界模型中,同时绘制了多个物体,那么怎么去检测物体之间是否触碰了,不同于在平面之间的触碰,OpenGL 是在三维世界里面的触碰,接下来就继续深入理解 OpenGL 中的碰撞检测相关知识~~~
2018-07-24 09:39:10
在前面的系列文章中,分别介绍了 OpenGL 的环境光、散射光、镜面光。
现在尝试将这些光照效果混合起来,让整个场景显得更加逼真。
具体的效果如下:
2018-07-20 14:50:22
避免图片丢失,建议阅读微信原文:
在 OpenGL 世界里,使用深度测试可以来防止被阻挡的面渲染到其他面的前面。
直接看一个没有使用深度测试的绘制:
按照计划是绘制一个封闭的立方体,六个面都是有的,可从上面的效果来看并不是,立方体的有些面丢失了,只有后面的那个面,前面的面没了。
这就是在没有开启深度测试的情况下,本来应该被遮挡的,绘制在后面的面却绘制到了其他面之上。
要解决这种问题,就得使用深度测试了。
2018-07-19 11:45:15
避免图片丢失,建议阅读微信原文:
现在我们用 OpenGL 绘制了如下的立方体:
不管我们怎么旋转立方体,从任何一个方向去看它,最多都只能看到三个面。
那么对于 OpenGL 来说,那看不到的另外三个面完全可以不用绘制它,从而提高绘制的性能。
2018-07-18 23:16:22
在之前使用 OpenGL 顶点缓冲区 VBO 的使用 为顶点坐标、纹理坐标分别绑定了顶点缓冲区,并且在 onDrawFrame 方法里面也要分别为顶点坐标、纹理坐标指定数据。
这就存在了一些重复的操作。
在 OpenGL ES 3.0 可以使用顶点数组对象来解决这一问题。
2018-07-17 22:28:37
在之前的绘制过程中,首先都需要将物体的顶点数据保存在内存中,然后 glDrawArrays
或 glDrawElements
绘制前,将顶点数据送入到显存中,这样会存在 I/O 开销较大的问题,性能也不够好。
可以将顶点数据存放在顶点缓冲区中,就不需要在每次绘制前把顶点数据复制进显存,而是在初始化顶点缓冲区对象时一次性将顶点数据送入显存,每次绘制时直接使用显存中的数据,可以大大提高渲染性能。
2018-07-16 11:13:19
避免图片丢失,建议阅读微信原文:
在 Android 中有一个类 PorterDuffXfermode ,它是用来设置颜色混合方式的,也就是在已有颜色的基础上再绘制一笔颜色,这两个颜色是如何进行混合的,是新绘制的颜色覆盖了原有颜色,还是新绘制的颜色和原有颜色混合组成另一种颜色呢。
在 OpenGL 中同样有这样颜色混合的问题。
2018-07-13 09:41:22
在前面的博客文章中有提到 OpenGL 裁剪测试及注意点,并且裁剪测试只能裁剪一个矩形区域,相当于就是把整个内容都绘制上去了,但是透过一个小矩形区域来看绘制的物体。
除了透过矩形区域,还可以实现透过任意形状区域来观察物体,这就是要用到 OpenGL 的 Alpha 透明度测试。
关于 Alpha 透明度测试,在 用 OpenGL 对视频帧内容进行替换 也用实践用到过。
2018-07-12 16:59:47
避免图片丢失,建议阅读微信原文:
在群里面有人提到了这么一个实现:现有一段素材视频,想要对视频中的某个内容进行替换,换成自己的图片,这个怎么用 OpenGL 去实现呢?
2018-07-11 14:25:52
学习了一段时间的 OpenGL ES,并在公司的项目中得到了运用,也算是有了一些积累,现在分享一些当初学习的资源,大家一起来学习,共同交流进步。
2018-07-03 21:35:34
在 OpenGL 中启用裁剪测试可以在屏幕或者帧缓冲上指定一个矩形区域,然后在该矩形区域内绘制,只有在该区域内的片元才有机会最终进入帧缓冲,不在该区域内的将会被丢弃。
2018-07-02 23:37:16
避免图片丢失,建议阅读微信原文:
在使用 OpenGL 绘制时,我们最多绘制的是一些简单的图形,比如三角形、圆形、立方体等,因为这些图形的顶点数量不多,还是可以手动的写出那些顶点的,可要是绘制一些复杂图形该怎么办呢?
2018-06-29 20:31:53
在 Kotlin 有一些可以简化代码的语法糖,比如 run、let、with、apply、also、takeIf、takeUnless 等。
再不明白这些语法糖的情况下去看 Kotlin 代码就会一脸懵逼,可当明白之后就会觉得原来可以这样简化。
2018-05-25 19:47:29
避免图片丢失,建议阅读微信原文:
在之前的绘制中,我们都是通过 glDrawArrays
方法来实现的,它会按照我们传入的顶点顺序和指定的绘制方式进行绘制。
回顾一下之前提到的绘制类型:
绘制类型 | 绘制方式 |
---|---|
GL_POINTS | 将传入的顶点坐标作为单独的点绘制 |
GL_LINES | 将传入的坐标作为单独线条绘制,ABCDEFG六个顶点,绘制AB、CD、EF三条线 |
GL_LINE_STRIP | 将传入的顶点作为折线绘制,ABCD四个顶点,绘制AB、BC、CD三条线 |
GL_LINE_LOOP | 将传入的顶点作为闭合折线绘制,ABCD四个顶点,绘制AB、BC、CD、DA四条线。 |
GL_TRIANGLES | 将传入的顶点作为单独的三角形绘制,ABCDEF绘制ABC,DEF两个三角形 |
GL_TRIANGLE_STRIP | 将传入的顶点作为三角条带绘制,ABCDEF绘制ABC,BCD,CDE,DEF四个三角形 |
GL_TRIANGLE_FAN | 将传入的顶点作为扇面绘制,ABCDEF绘制ABC、ACD、ADE、AEF四个三角形 |
2018-05-22 12:04:10
避免图片丢失,建议阅读微信原文:
在 OpenGL 投影矩阵 这篇文章中,讲述了 OpenGL 坐标系统中的投影矩阵,有两种类型的投影矩阵,分别是正交投影和透视投影。
这两种投影实质上是两种类型的裁剪空间,分别创建对应视景体对物体坐标进行裁剪,位于裁剪空间内的才会被映射到屏幕上,如下图所示:(图片来源:https://glumpy.github.io/modern-gl.html)
当定义裁剪空间视景体时,我们都需要提供近平面和远平面的距离,这里的近和远都是指相对于视点
的,视点也就是我们这篇文章要讲到的摄像机。
2018-05-16 17:55:52
Android JNI 调用时的异常主要有如下两种:
2018-05-16 17:50:06
在 Native 代码中有时候会接收 Java 传入的引用类型参数,有时候也会通过 NewObject 方法来创建一个 Java 的引用类型变量。
在编写 Native 代码时,要注意这个代表 Java 数据结构类型的引用在使用时会被 GC 回收的可能性。
2018-05-07 10:39:50
在 JNI 去调用 Java 的方法和访问字段时,最先要做的操作就是获得对应的类以及对应的方法 id。
事实上,通过 FindClass 、GetFieldID、GetMethodID 去找到对应的信息是很耗时的,如果方法被频繁调用,那么肯定不能每次都去查找对应的信息,有必要将它们缓存起来,在下一次调用时,直接使用缓存内容就好了。
缓存有两种方式,分别是使用时缓存和初始化时缓存。
2018-05-07 10:32:01
Android 还可以通过 JNI 来调用 Java 一个类的构造方法,从而创建一个 Java 类。
2018-05-07 10:27:08
在前面的两篇文章中,介绍了 Android 通过 JNI 进行基础类型、字符串和数组的相关操作,并描述了 Java 和 Native 在类型和签名之间的转换关系。
有了之前那些基础,就可以实现 Java 和 Native 的相互调用了,在 Native 中去访问 Java 类的字段并调用相应的方法。
2018-05-07 09:44:57
自从 Android Studio 升级到 2.3 版本以后,使用 CMake 进行编译就方便多了,不需要再写 Android.mk 了,也不需要用 javah 来生成头文件了,直接写好 native 方法,快捷方式就可以生成对应的 C++ 方法,只要专注写好 C++ 代码,CMake 就可以指定的 CPU 架构生成对应的 SO 库。
2018-04-12 13:13:57
要了解 Android Camear 相机模型的演变,首先还是得了解硬件抽象层 HAL 相关的知识内容。
2018-04-10 16:09:32
*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
在 Android Camera 开发中,两个比较闹心的问题就是尺寸和方向了。
2018-01-31 15:31:44
花了一两天时间终于在 Mac 上成功编译了 Android 主线最新代码,中间遇到了不少问题,也查阅了好多资料,总算是成功了,看到模拟器启动的那一刻还是挺激动的。
2018-01-24 18:17:58
避免图片丢失,建议阅读微信原文:
在 OpenGL 坐标系统 文章中,根据点的坐标变换得出了如下的公式:
这个公式每左乘一个矩阵,都代表了一种坐标系的变换。
转化为着色器脚本语言如下:
attribute vec4 a_Position;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ProjectionMatrix;
uniform mat4 u_ViewMatrix;
void main()
{
gl_Position = u_ProjectionMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;
}
本篇文章就主要是对投影矩阵来分析的。
2018-01-23 17:44:53
避免图片丢失,建议阅读微信原文:
在前面绘制基本图形中,遇到了很明显的问题,圆形不像圆形,正多边形不像正多边形?就像下面图形一样:
好好的正五边形却东倒西歪的,这就是因为我们前面的绘制都是把它当成 二维 的绘制,而在 OpenGL 中却是绘制 三维的。在二维和三维之间还有个转换,而之前为了方便学习则忽略了这个转换,现在就要开始理解它了 —— 坐标系统
!!
2017-12-22 16:21:16
在之前的一篇博客中,讲述了 OpenGL 绘制一个点的流程及相关的代码,其中关于 OpenGL 程序编译部分都是可以在其他项目中接着复用的,接下来会讲到如何去绘制其他的基本图元。
2017-12-22 16:10:57
函数式编程是一种编程范式,不同于之前的面向对象编程。它是面向数学的抽象,也就是说,这里的函数
二字不再是我们编程语言中的函数,而是数学中的函数
了。
2017-12-22 16:08:45
正如标题所言,docopt 是一个用来解析命令行参数的工具,当想要在 Python 程序后面附加参数时,就不需要再为此而发愁了。
docopt 是一个开源的库,代码地址:https://github.com/docopt/docopt。它在 README 中就已经做了详细的介绍,并且还附带了很多例子可供学习,这篇文章也是翻译一下 README 中内容……
2017-12-22 16:05:30
有了上一篇文章基础,这里就只关注 FFmpeg 如何解析的具体实践了。
在开始工程之前,第一步要做的就是编译 FFmpeg 源码,生成 Android 平台上使用的 so 库。
在生成完了之后,导入 Android 工程项目中,并且配置 CMake 文件,添加对应的库,就可以开始开发了。
2017-12-22 16:03:10
最近在研究学习 FFmpeg,从网上参考了好多资料,其中最了不起的就当属——雷霄骅大神了,若没有他的博文,别说入门了,可能连门在哪里都不知道,在此还是要表达一下对雷神的敬佩和敬仰。
本文主要讲的是视频文件的解码,从视频文件的封装格式解码到原始数据格式,通过讲解涉及到的各种概念,从而理清整个思路和流程。
2017-12-22 16:00:05
之前有写过一篇文章:用 RxJava 封装回调方法 CallBack。
RxJava 封装回调方法的大体思路就是:使用 Observable 的 create 方法来返回一个 Observable,在 create 方法内给事物设置回调接口,用 Observable 的 onNext 方法来接受回调接口所产生的内容。
这样一来,通过 onNext 方法就把事物的回调方法转换到 Rxjava 对应的事件流里面了,再可以通过其他操作符,如 Map、FlatMap 等对事件流进行相应的转换。
2017-12-22 15:55:08
Activity 在界面创建时需要将 XML 布局文件中的内容加载进来,正如我们在 ListView 或者 RecyclerView 中需要将 Item 的布局加载进来一样,都是使用 LayoutInflater 来进行操作的。
LayoutInflater 实例的获取有多种方式,但最终是通过(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
来得到的,也就是说加载布局的 LayoutInflater
是来自于系统服务的。
2017-12-22 15:40:19
Service 组件也是 Android 四大组件之一,它的启动过程分为显示和隐式两种。对于隐式启动的 Service 组件来说,我们只需要它的组件名称;对于显示启动的 Service 组件来说,我们需要知道它的类名称。
Service 组件可以被 Activity 组件启动,也可以被其他的 Service 组件启动。同时,它既可以在启动它的 Activity 组件或者 Service 组件所在的应用程序中启动,也可以在一个新的应用程序进程中启动。
2017-12-22 15:37:04
之前就有写过一篇文章来学习状态机:状态机学习。
在之后的工作中多次用到了 StateMachine 状态机,简单记录其原理。
2017-12-22 15:35:23
LruCache 是安卓开发中常用到的缓存技术,LRU 的全名是 Least Recently Used,表示最近最少使用算法,也就是说当内存快到达阈值时,若某个对象最近很少使用的,那么它就会被回收掉以释放内存。
2017-12-22 15:33:22
在之前有分析过 Android 6.0 Launcher 启动 Activity 过程,文章的链接如下:
2017-12-22 15:30:26
在之前 Android 系统服务管理 ServiceManager 中学习了各种系统服务 Service 都是通过 ServiceManager
来管理的,从 ServiceManager 中来获得系统服务的 Binder 对象引用。这内容涉及到了 ContextImpl
类、SystemServiceRegistry
类、ServiceManager
类、ServiceManagerNative
类等等。
那么问题就来了,ServiceManager 所管理的那些 Service 的 Binder 对象引用又是何时注册添加的呢?
事实上这些服务 Service 是 SystemServer 进程中启动的。
2017-12-22 15:27:11
在应用程序编程时,经常使用到 getSystemService(String serviceName) 方法来获得一个系统服务,它的实现也是在 ContextImpl 中的,根据不同的参数返回不同的系统服务,这些系统服务都是由 ServiceManager 管理的。
2017-12-22 10:50:43
Binder 是什么?在英文中 Binder 是 粘合剂 的意思,表示将两样东西粘在一起。而在 Android 开发中,Binder 的意思多了去了。不同的角度有着不同的解释。
它既可以是 Android 中实现了 IBinder 接口的一个单纯的类,也可以是 Android 中进程跨进程通信(IPC)的一种方式,还可以看作是工作在内核态的 Linux 驱动 /dev/binder
。
2017-12-22 10:47:52
Dagger2 是一个进行依赖注入的框架,早先是由 Square 公司写的,后来由 Google 来维护了,能由 Google 亲自维护的东西,肯定值得学习。
2017-12-22 10:40:49
在如下三篇文章中过了一遍 Launcher 启动 Activity 的代码流程。
然而, 即使看过了多遍代码流程依旧有点云里雾里的感觉。不从整体上来把握,光抓住细节代码会始终不得要领。
由于是从 Launcher 组件启动一个 Activity 组件,其中还需要与 ActivityManagerService 通信,而这三个部分都是位于不同的进程内,涉及进程间通信,因此可以将整个过程划分为三个不同的部分来分析,在 Launcher 进程内的操作,在 ActivityManagerService 进程内的操作,在创建的应用程序进程内的操作。
2017-12-22 10:40:45
在 Android 6.0 Launcher 启动 Activity 过程源码分析(二) 分析完了对待启动 Activity 组件的验证过程,获得组件信息,以及 ActivityRecord 添加至栈顶,将其他 Activity 进入中止状态,最后将待启动的 Activity 组件进入 Resumed
状态,然而,由于待启动的 Activity 组件的应用程序进程尚未启动,最后执行 startSpecificActivityLocked
方法创建进程。
2017-12-22 10:40:42
在 Android 6.0 Launcher 启动 Activity 过程源码分析(一) 分析完了 Launcher 组件中启动的步骤,接下来的环节是该 ActivityManagerService 出场了。
通过 ActivityManagerNative.getDefault() 方法得到 ActivityManagerService 的代理对象后执行的 startActivity 方法,最终会发起进程间通信请求,通过 Binder 驱动,再调用 ActivityManagerService 中对应的方法。
2017-12-22 10:40:38
当 Android 系统在启动时,会扫描系统特定目录,然后自动安装里面的 Android 应用程序。当系统启动完成之后,会启动一个 Home 应用程序来显示安装在系统中的 Android 应用程序。
这个应用程序就是 Launcher 应用,也就是手机屏幕上显示的各种应用图标,Launcher 是 Android 系统启动的第一个应用程序。
而当我们点击应用程序图标时,也就开启了从 Launcher 启动 Activity 的过程。
2017-12-22 10:38:34
在知乎上看到这样一个问题:RxJava正确的封装callback的方式应该是怎么样的?。虽说已经是个一年前的问题了,自己现在才遇到 (羞愧脸) 。
2017-12-22 10:31:13
Android 从 5.0 开始使用新的相机 API Camera2 来代替之前的旧版本,从而支持更多的特性。
在学习新的 API 调用之外,也还是要了解一下 Android 底层发生了哪些变化,从而能够让我们对 API 的调用流程更加的清晰,知其所以然。
2017-12-20 15:23:52
关于本站 你好,欢迎访问 https://glumes.com 🎉🎉🎉 本站作为个人博客,主要是记录在软件开发、音视频、图像渲染方面的积累,也会分享一些日常生活中有趣的事情。 欢迎在本站留言交流!! 关于我 我的星陨, 个人经历 2012.9 — 2016.7 : 西安电子科技大学 生物技术专业,后来生活所迫就 Just Do IT 。 2016.7 — 2017.5 : 珠海魅族科技 参与智能硬件 App 开发, 毕业后第一份工作,不得不说珠海是个美丽的地方,让人难忘。 2017.5 — 2019.2 : 广州视源股份 有一说一,CVTE 的餐饮、医疗、健身等服务还是很周到的。 2019.2 — 2021 : 深圳字节跳动 心脏和字节只有一个能跳动,卷不动了!!! 社交 毕业于西安电子科技大学🏫,曾就职于珠海魅族📱,后来到了广州CVTE搬砖🍭,目前在字节跳动深圳分部。珠三角都留下了我的踪迹~~~ 近期技术聚焦在 OpenGL ES 图形、图像和音视频领域💪,从事画板🎨和相机📷及相关 Android 应用开发,从事音视频编辑及相关应用开发。 博客主要记录个人在技术、工作、生活方面的思考和感悟~~~🤔🤔🤔 对技术充满兴趣,喜欢并乐于探索各种方面的可能性,喜欢 陆游 的那句诗: 纸上得来终觉浅,绝知此事要躬行 选择比努力更重要,坚持正确的方向,终究会量变到质变~ 转向采用 Kotlin 和 Cpp 来做主力开发语言,也会用到 Python 等。 有个微信公众号 音视频开发进阶, 欢迎关注,及时看到最近的文章和状态。 另外,这是我的 掘金主页 ,还有一个喜爱转发的微博账户,可以加我微信: ezglumes (备注:姓名+城市),一起交流技术、工作与生活~~~
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52
2017-12-20 15:23:52