InfoQ Geekathon 大模型技术应用创新大赛 了解详情
写点什么

Kotlin/Native 应用程序开发指南

  • 2018-03-13
  • 本文字数:2149 字

    阅读完需:约 7 分钟

在这篇博文中,我们将讨论 Kotlin/Native 应用程序的开发。在这里,我们使用 FFMPEG 音频 / 视频解码器和 SDL2 进行渲染,来开发个简易的视频播放器。希望此文可以成为能对 Kotlin/Native 开发者有价值的开发指南,同时该文也会解释使用该平台的预期机制。

在本教程中,我们主要关注的是 Kotlin/Native,我们只会粗略地介绍一下如何开发视频层。您可以参阅这篇名为《如何用不到1000 行代码编写一个视频播放器》的优秀教程,以了解如何用C 语言实现它。如果您的兴趣点在于比较C 语言的编码与Kotlin/Native 编码的不同之处,我建议您从本教程开始。

理论上,每一个视频播放器的工作都相当简单:读入带有交错的视频帧和音频帧的输入流,解码并显示视频帧,同时与音频流同步。通常,这一工作由多个线程完成,执行流解码、播放视频和音频。要准确的做到这些,需要线程同步和特定的实时保证,如果音频流没有被及时解码,播放声音听起来会很不稳定,如果视频帧没有及时显示,影像看起来会很不流畅。

Kotlin/Native 不鼓励您使用线程,也不提供在线程之间共享 Kotlin 对象的方法。然而,我们相信在 Kotlin/Native 中并发的软实时编程很容易实现,所以我们决定从一开始就以并发的方式来设计我们的播放器。来看看我们是怎么做到的吧。

Kotlin/Native 计算并发性是围绕 workers 构建的。Worker 是比线程更高级的并发性概念,不像对象共享和同步,它允许对象传输,因此每一时刻只有一个 workers 可以访问特定对象。这意味着,访问对象数据时不需要同步,因为多个访问永远不能同时进行。workers 可以接收执行请求,这些请求可以接受对象并根据需要执行任务,然后将结果返回给需要计算结果的人。这样的模型确保了许多典型的并发编程错误 (例如对共享数据的不同步访问,或者由未排序的锁导致的死锁) 不再出现。

让我们看看,它是如何转化为视频播放器架构的。我们需要对某些容器格式进行解码,比如 avi .mkv 或者 .mpg ,它对交叉音频和视频流进行多路分解、解码,然后将解压缩的音频提供给 SDL 音频线程。解压后的视频帧应与声音播放同步。为了达到这个目标,worker 概念的出现也便是理所当然的了。我们为解码器生成一个worker,并在需要的时候向它请求视频音频数据。在多核机器上,这意味着解码可以与播放并行进行。因此,解码器是一个来自UI 线程和音频线程的数据生成器。

无论何时我们需要获取下一个音频或视频数据块时,我们都依赖于全能的 schedule() 函数。它将调度大量的工作给特定的 worker 执行,以便提供输入参数和返回 Future 实例,这些可能被挂起,直到任务被目标 worker 执行完。Future 对象可能被销毁,因此产生的对象将直接从 worker 线程返回到请求程序线程。

Kotlin/Native 运行时理论上讲是线性的,所以当运行多个线程时,需要在做其他操作之前调用函数 konan.initRuntimeIfNeeded() ,我们在音频线程回调中也是这样做的。为了简化音频播放,我们将音频帧重新采样到两个通道,并以 44100 的采样率对 16 位整数流进行标识

视频帧可以被解码成用户需要的大小,当然它会有个默认值,同时它的位深度依赖于用户桌面默认设置。还请注意下Kotlin/Native 特有的操作C 指针的方法,即

复制代码
private val resampledAudioFrame: AVFrame =
        disposable(create = ::av_frame_alloc, dispose = ::av_frame_unref).pointed
...
with (resampledAudioFrame) {
    channels = output.channels
    sample_rate = output.sampleRate
    format = output.sampleFormat
    channel_layout = output.channelLayout.signExtend()
}

我们声明 resampledAudioFrame 作为由 FFMPEG API 调用 avframealloc() 和 avframeunref() 创建的 C 程序中的一次性资源。然后,我们将它所指向的值设置成它所期望的字段。需要注意的是,我们可以将 FFMPEG(如 AV_PIX_FMT_RGB24 ) 声明的定义作为 Kotlin 的常量。但是,由于它们没有类型信息,并且默认情况下是 Int 类型的,如果某个字段具有不同的类型 (比如 channellayout),那便需要调用适配器函数 signExtend() 。这是编译器的内在特性,它会插入适当的转换中

在设置完解码器后,我们开始播放流程。这没有什么特别的,只是检索下一个帧,将它呈现给纹理,并在屏幕上显示这个纹理。至此,视频帧便被渲染了。音频线程回调是由音频线程回调处理的,它从解码器中获取下一个采样缓冲区,并将其反馈给音频引擎。

音频/ 视频同步是必须要保证的,它可以确保我们没有太多的未播放的音频帧。真正的多媒体播放器应该依赖于帧时间戳,我们只计算它,但永远不会使用。这里有一个有趣的地方

复制代码
val ts = av_frame_get_best_effort_timestamp(audioFrame.ptr)
  av_q2d(audioCodecContext.time_base.readValue())

它展示了如何使用 api 接收 C 语言的结构体。它是在 libavutil/rational.h 中声明的

复制代码
static inline double av_q2d(AVRational a){
    return a.num / (double) a.den;
}

因此,要通过值传递它,我们首先需要在字段上使用 readValue()。

总结来说,多亏了 FFMPEG 库,我们才能用较少的代价便实现了一个支持多种输入格式的简易音频 / 视频播放器。这里我们还讨论了 Kotlin/Native 中基于 C 语言的互操作性相关的基础知识,以及更容易使用和维护的并发方法。

英文原文链接 Application development in Kotlin/Native

感谢冬雨对本文的审校。

活动推荐:

2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。

2018-03-13 18:302723

评论

发布
暂无评论
发现更多内容

Nacos-spring-boot 0.2.10 发布,全面支持 Nacos2.0

阿里巴巴中间件

云计算 开源 云原生 中间件

【ClickHouse】 核心特性

LeifChen

Clickhouse 8月日更

全靠阿里内部(珠峰版)Java面试笔记,成功拿下12家大厂offer

编程菌

Java 编程 程序员 阿里 计算机

在线CSS代码压缩美化工具

入门小站

工具

平台利用大数据割韭菜,消费者为何沦为砧板上的鱼肉

石头IT视角

架构实战营 - 模块 5- 设计微博系统中”微博评论“的高性能高可用计算架构

蔸蔸

【设计模式】策略模式

Andy阿辉

C# 后端 设计模式 8月日更

干货来袭!阿里技术官甩出的内部首推分布式系统开发笔记太顶了

编程菌

Java 编程 程序员 面试 计算机

有了阿里人的并发图册+JDK源码速成笔记,我终于不慌内卷了

编程菌

Java 编程 程序员 面试 计算机

从零开始的SRC挖掘

网络安全学海

黑客 网络安全 信息安全 渗透测试 漏洞挖掘

模块五作业:设计微博评论的高性能高可用计算架构

Felix

MongoDB中间件工具mgm入门介绍(一)

liuzhen007

8月日更

阿里架构师花近十年时间整理出来的Java核心知识pdf(Java岗)

编程菌

Java 编程 程序员 面试 计算机

常见酒店行业术语

IT蜗壳-Tango

8月日更

架构实战营模块五作业

袁小芬

【架构训练营】模块五作业

zclau

模块五作业

king

阿里P8整理的《百亿级并发系统设计》实战教程,实在是太香了

编程菌

Java 编程 程序员 阿里 计算机

架构实战营作业 M05

Shawn Liu

架构实战训练营第五模块作业

子豪sirius

架构实战营

有同学问我:Fetch 和 Ajax 有什么区别?

编程三昧

JavaScript ajax 大前端 8月日更 Fetch

模块五作业

绝影

架构训练营

前端之算法(八)贪心算法

Augus

算法 8月日更

PAI:一站式云原生AI平台

阿里云大数据AI技术

”微博评论“的高性能高可用计算架构

feitian

架构训练营 模块五

小卷儿

[架构实战营一期] 模块五作业

trymorewang

架构实战营

【SpringCloud技术专题】「Feign技术专区」从源码层面让你认识Feign工作流程和运作机制

洛神灬殇

OpenFegin spring-cloud Fegin 8月日更

真的香!Github一夜爆火被各大厂要求直接下架的面试题库也太全了

编程菌

Java 编程 程序员 面试 计算机

微服务的演进之路

卢卡多多

微服务 8月日更

模块五作业-微博评论-高性能高可用架构

babos

#架构实战营

  • 扫码添加小助手
    领取最新资料包
Kotlin/Native应用程序开发指南_语言 & 开发_Nikolay Igotti_InfoQ精选文章