Kotlin/Native應用程式開發指南

來源:互聯網
上載者:User

Kotlin/Native應用程式開發指南

在這篇博文中,我們將討論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

本文永久更新連結地址:https://www.bkjia.com/Linux/2018-03/151371.htm

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.