1. 程式人生 > >Application development in Kotlin/Native

Application development in Kotlin/Native

In this blog post we are discussing development of Kotlin/Native applications. Today we take a look on basic video player, using FFMPEG audio/video decoder and SDL2 for rendering. Hopefully, it will be useful guide for Kotlin/Native development enthusiasts and will explain intended mechanisms of using the platform.

As main focus in our tutorial is on Kotlin/Native, we will give only cursory view on how videoplayer shall be developed. Please see this excellent tutorial, called “How to Write a Video Player in Less Than 1000 Lines” for reference on how it could be done in C language. If you’re interested in comparing how coding in C differs to coding in Kotlin/Native, I would recommend starting with this tutorial.

Every video player in theory does rather simple job: reads input stream with interleaved video and audio frames, decodes frames and shows video frames, synchronising them with the audio stream. Typically, this job is being done by multiple threads, performing stream decoding, video and audio playback. Doing it right requires thread synchronisation and certain real-time guarantees, as if audio stream is not being decoded in time, playback sounds choppy, and if video frame is not available when it’s needed, movie doesn’t look smooth.

Kotlin/Native doesn’t encourage you to use threads, and doesn’t provide a way to share Kotlin objects between threads. However, we believe that concurrent, soft-realtime programming in Kotlin/Native shall be easy, so we decided to design our player in concurrent manner from the very beginning. Let’s see how we achieved that.

Kotlin/Native computational concurrency is built around  workers. Worker is higher level concurrency concept than thread, and instead of object sharing and synchronisation it allows object transfer, so that every moment only single workers have access to particular object. It means, no synchronisation shall be required to access object data, as access could never be concurrent. Workers can receive execution requests, which may accept objects and perform job as needed, and then transfer result back to whoever need computation’s result. Such model ensures that many typical concurrent programming mistakes (such as unsynchronised access to shared data, or deadlocks because of unordered taking of locks)  just cannot be made.

Let’s see, how it translates to the video player architecture. We need to perform decoding of some container format, like .avi, .mkv or .mpg, which perform demultiplexing of interleaved audio and video streams, decoding and then feed decompressed audio to SDL audio thread. Decompressed video frames shall be rendered in sync with sound playback. To achieve that goal, worker’s concept seems to be pretty natural. We spawn a worker for the decoder, and ask it for video and audio data whenever we need it. On multicore machines it means that decoding can happen in parallel with the playback. So decoder worker is a data producer from both UI thread and audio thread.

Whenever we need to fetch next audio or video data chunk, we rely upon almighty schedule() function. It schedules chunk of work to be executed by a particular worker, provides input argument and return Future instance, that could be waited on, until job is executed by the target worker. Future object could be consumed, so that produced object is taken from worker thread back to requester thread.

Kotlin/Native runtime is conceptually thread-bound, so when running multiple threads calling function konan.initRuntimeIfNeeded() is required before other operations, so we do that in audio thread callback. To simplify audio playback we always resample audio frames to 2 channel signed 16-bit integer stream with 44100 samples per second.

Video frames are being decoded to whatever size is requested by the user, with defaults of encoded video size, and bit depth depends on user’s desktop defaults.  Please note Kotlin/Native specific operations for manipulating C pointers, i.e.

JavaScript
123456789 privateval resampledAudioFrame:AVFrame=disposable(create=::av_frame_alloc,dispose=::av_frame_unref).pointed...with(resampledAudioFrame){channels=output.channelssample_rate=output.sampleRateformat=output.sampleFormatchannel_layout=output.channelLayout.signExtend()}

We declare resampledAudioFrame being a disposable resource in the C world created with FFMPEG API call av_frame_alloc() and disposed with av_frame_unref(). Then we set fields of whatever it points to to the desired values. Note that we can use defines declared by FFMPEG (such as AV_PIX_FMT_RGB24) as Kotlin constants. But as they do not have type information and are Int by default, if certain field has different type (i.e. channel_layout) adapter function signExtend() must be called. It is compiler’s intrinsic, which inserts appropriate conversions.

After decoder is set up, we start the playback loop. It does nothing fancier but retrieves the next frame, renders it to the texture and shows this texture on the screen. As a result – video frame is rendered. Audio is being actively handled by audio thread callback which fetches next samples buffer from the decoder and feeds it back to audio engine.

Audio/video synchronisation is pretty basic, it just ensures that we don’t have not too many unplayed audio frames.  Real multimedia player probably shall rely on frame timestamps instead, which we compute, but never use.  Here interesting place is using

JavaScript
12 val ts=av_frame_get_best_effort_timestamp(audioFrame.ptr)*av_q2d(audioCodecContext.time_base.readValue())

It manifests how to use APIs accepting C language struct’s. It is declared in libavutil/rational.h as

C
123 staticinlinedoubleav_q2d(AVRationala){returna.num/(double)a.den;}

Thus, to pass it by value, we first need to use readValue() on the field.

So, as a wrap up, we have implemented a simple audio/video player supporting multiple input formats, thanks to FFMPEG library, with relatively minor efforts. We also discussed some basics of  C language interoperability in Kotlin/Native, along with concurrency approaches we consider easier to use and maintain.

相關推薦

Application development in Kotlin/Native

In this blog post we are discussing development of Kotlin/Native applications. Today we take a look on basic video player, using FFMPEG audio/

Lambdas in Kotlin, and how they simplify Android development (KAD 07)

Lambdas are one of the most powerful tools in Kotlin, and in any other modern language, since it allows modelling functions in a much simpler way. Th

Online Game Development in C++ 第五部分總結

無限 asa 搜索 清理 屬性 line 而且 驅動力 c函數 教程案例框架描述 該套教程做了一個簡單的汽車控制系統,沒有用到物理模擬。用油門和方向控制汽車的加速度和轉向,同時還有一些空氣阻力和滾動摩擦力的設置增加了真實感。汽車的位置是通過加速度和時間等計算出來的。 關鍵的

[React Native] Reduce Long Import Statements in React Native with Absolute Imports

other absolute fig Go react project only port gen In large React Native projects, it’s common to have long relative import paths li

CS2204 Fundamentals of Internet Application Development

代做CS2204留學生作業、代寫HTML5語言作業、代做Internet Application Development作業、代寫HTML/CSS/Web作業Department of Computer ScienceCity University of Hong KongCS2204 Fundamental

IDEA執行kotlin native

今天試了下kotlin native,好久沒玩過這個玩意兒了。 然後建了一個kotlin native的工程 發現IDEA一直在說是多平臺專案 Kotlin Multiplatform Projects are an experimental feature. 執行kotlin na

JetBrains開發者日見聞(一)之Kotlin/Native 嚐鮮篇

簡述: 今天我們來講點Kotlin中比較時髦的東西,有的人可能會說:“不像你之前的風格啊,之前的文章不是一直在死扣語法以及語法糖背後祕密。當你還在死扣泛型語法的時候,別人的文章早就說了Kotlin/Native和Kotlin1.3的新特性”。瞬間感覺自己out了,今天我們就說說這些時髦的東西,也許你能看到一些

《Boost C++ Application Development Cookbook》筆記(持續更新)

小試牛刀 可用boost::optianal來作為函式返回值的標識,函式返回值用來表示函式是否執行成功,但如果執行成功但沒有正確的結果,這種情況則可以藉助boost::optianal來實現 boost::array 函式返回陣列可以用array,不用擔心資料越界等問題

Kotlin/Native Tech Preview: Kotlin without a VM

We are happy to announce the first Technology Preview of Kotlin/Native that compiles Kotlin directly to machine code. The Kotlin/N

Gracefully handling application exceptions in a Tornado application

之前在DigitalOcean 的主機上用wordpress架了一個web site站臺,只使用了 port 80, 後來在 443 port 架了 tornado, 滿神奇的,tornado 可以直接使用 letsencrypt 的憑證檔案。 後來發現 googlebot 會來parse 443 port

How to structure your project and manage static resources in React Native

How to structure your project and manage static resources in React NativeReact and React Native are just frameworks, and they do not dictate how we should

D look at embryonic development in living mice

For the first time, researchers can now peek inside a living mouse embryo and watch the gut begin to form and heart cells take their first tentative beats

Listeners with several functions in Kotlin. How to make them shine?

One question I get often is how to simplify the interaction with listeners that have several functions on Kotlin. For listeners (or any interfaces) w

Routing in React Native apps and how to configure your project with React

Tab Navigator implements a type of navigation that exists in native iOS for many years already. Recently, Android added it to its Material design patterns

How Decentralized Application Development Nearly Destroyed My World

How Decentralized Application Development Nearly Destroyed My WorldBy Rob Misiorowski, OpenBazaar Front End DeveloperOk, that title is a little hyperbolic,

location and App Permissions in React Native and Expo

In web, Geolocation is provided as an API that has different methods to use in a web application. Similarly, React Native takes advantage of this API and i

MQ JMS application development with Spring Boot

IBM MQ has a Spring Boot Starter, allowing Spring developers an easy way to configure the IBM MQ JMS package. MQ enables applications

Setting up ESLint and EditorConfig in React Native projects

Setting up ESLint and EditorConfig in React Native projectsI had a hard time going from 4 spaces to 2 spaces indentation, now I’m quite comfortable with it

Position element at the bottom of the screen using Flexbox in React Native

Position element at the bottom of the screen using Flexbox in React NativeSource: British AirwaysReact Native uses Yoga to achieve Flexbox style layout, wh

Women Seen Making Inroads into AI Development in 2018

Let’s make one thing clear: one year isn’t going to fix decades of gender discrimination in computer science and all the problems