diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index d3637ef..2a33f70 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -35,18 +35,6 @@ "pinned": true } }, - { - "id": "de527c8685894116", - "type": "leaf", - "state": { - "type": "markdown", - "state": { - "file": "04. Programming/Kotlin/run, let, with, also 和 apply.md", - "mode": "source", - "source": true - } - } - }, { "id": "0c4cc0216ea83049", "type": "leaf", @@ -58,9 +46,33 @@ "source": true } } + }, + { + "id": "6fe3a34cb01785c6", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "03. 專注Study/Android/Android programming.md", + "mode": "source", + "source": true + } + } + }, + { + "id": "02d3631a7d6b4afa", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "03. 專注Study/Android/MediaCodec.md", + "mode": "source", + "source": true + } + } } ], - "currentTab": 1 + "currentTab": 4 } ], "direction": "vertical" @@ -118,7 +130,7 @@ "state": { "type": "backlink", "state": { - "file": "00. Inbox/01. TODO.md", + "file": "03. 專注Study/Android/MediaCodec.md", "collapseAll": false, "extraContext": false, "sortOrder": "alphabetical", @@ -154,7 +166,7 @@ "state": { "type": "outline", "state": { - "file": "00. Inbox/01. TODO.md" + "file": "03. 專注Study/Android/MediaCodec.md" } } } @@ -180,9 +192,17 @@ "periodic-notes:Open today": false } }, - "active": "3b4577823cedf427", + "active": "02d3631a7d6b4afa", "lastOpenFiles": [ + "03. 專注Study/Android/Android External Storage - Read, Write, Save File.md", + "03. 專注Study/Android/Android programming.md", + "03. 專注Study/Android/ADB 取得 APK 的 icon.md", + "03. 專注Study/Android/MediaCodec.md", + "attachments/android_mediacodec_life_cycle.png", + "attachments/android_mediacodec_flow.png", "04. Programming/Kotlin/AtomicBoolean.md", + "04. Programming/Kotlin/class.md", + "04. Programming/Kotlin/`compareAndSet`.md", "00. Inbox/01. TODO.md", "04. Programming/Kotlin/run, let, with, also 和 apply.md", "05. 資料收集/軟體工具/git/tag.md", @@ -205,10 +225,6 @@ "02. 工作/01. Logitech/QA Sustaining Automation.md", "01. 個人/01. Daily/2023/02/2023-02-22(週三).md", "00. Inbox/Habit Tracker.md", - "01. 個人/01. Daily/2023/02/2023-02-12(週日).md", - "01. 個人/01. Daily/2023/02/2023-02-09(週四).md", - "01. 個人/01. Daily/2023/02/2023-02-11(週六).md", - "01. 個人/01. Daily/2023/02/2023-02-08(週三).md", - "02. 工作/01. Logitech/AE Team.md" + "01. 個人/01. Daily/2023/02/2023-02-12(週日).md" ] } \ No newline at end of file diff --git a/03. 專注Study/Android/Android External Storage - Read, Write, Save File.md b/03. 專注Study/Android/Android External Storage - Read, Write, Save File.md new file mode 100644 index 0000000..23dce04 --- /dev/null +++ b/03. 專注Study/Android/Android External Storage - Read, Write, Save File.md @@ -0,0 +1,5 @@ + + +## 參考資料 +- [Android External Storage - Read, Write, Save File | DigitalOcean](https://www.digitalocean.com/community/tutorials/android-external-storage-read-write-save-file) +- [Environment.getExternalStorageDirectory() is deprecated过时的替代方案_Mr_tigerchou的博客-CSDN博客](https://blog.csdn.net/shving/article/details/101057082) \ No newline at end of file diff --git a/03. 專注Study/Android/MediaCodec.md b/03. 專注Study/Android/MediaCodec.md new file mode 100644 index 0000000..15bfafa --- /dev/null +++ b/03. 專注Study/Android/MediaCodec.md @@ -0,0 +1,104 @@ +## 一般流程 +1. 使用者從MediaCodec請求一個空的輸入buffer(ByteBuffer),填充滿數據後將它傳遞給MediaCodec處理。 +2. MediaCodec處理完這些數據並將處理結果輸出至一個空的輸出buffer(ByteBuffer)中。 +3. 使用者從MediaCodec獲取輸出buffer的數據,消耗掉裡面的數據,使用完輸出buffer的數據之後,將其釋放回編解碼器。 + +流程如下圖所示: +![[android_mediacodec_flow.png]] + +## 生命週期 +MediaCodec的生命週期有三種狀態:Stopped、Executing、Released。 +- Stopped,包含三種子狀態:Uninitialized、Configured、Error。 +- Executing,包含三種子狀態:Flushed、Running、End-of-Stream。 +![[android_mediacodec_life_cycle.png]] + +**Stopped** 的三種子狀態: +1. Uninitialized:當創建了一個MediaCodec對象,此時處於Uninitialized狀態。可以在任何狀態調用reset()方法使MediaCodec返回到Uninitialized狀態。 +2. Configured:使用configure(…)方法對MediaCodec進行配置轉為Configured狀態。 +3. Error:MediaCodec遇到錯誤時進入Error狀態。錯誤可能是在隊列操作時返回的錯誤或者異常導致的。 + +**Executing** 的三種子狀態: +1. Flushed:在調用start()方法後MediaCodec立即進入Flushed子狀態,此時MediaCodec會擁有所有的緩存。可以在Executing狀態的任何時候通過調用flush()方法返回到Flushed子狀態。 +2. Running:一旦第一個輸入緩存(input buffer)被移出隊列,MediaCodec就轉入Running子狀態,這種狀態佔據了MediaCodec的大部分生命週期。通過調用stop()方法轉移到Uninitialized狀態。 +3. End-of-Stream:將一個帶有end-of-stream標記的輸入buffer入隊列時,MediaCodec將轉入End-of-Stream子狀態。在這種狀態下,MediaCodec不再接收之後的輸入buffer,但它仍然產生輸出buffer直到end-of-stream標記輸出。 + +**Released** +1. 當使用完MediaCodec後,必須調用release()方法釋放其資源。調用release()方法進入最終的Released狀態。 + +## API +### createEncoderByType +- [createEncoderByType](https://developer.android.com/reference/android/media/MediaCodec#createEncoderByType(java.lang.String)) + +### createDecoderByType +- [createDecoderByType](https://developer.android.com/reference/android/media/MediaCodec#createDecoderByType(java.lang.String)) + +### configure +- [configure]([MediaCodec  |  Android Developers](https://developer.android.com/reference/android/media/MediaCodec#configure(android.media.MediaFormat,%20android.view.Surface,%20android.media.MediaCrypto,%20int))) + +### start +- [start](https://developer.android.com/reference/android/media/MediaCodec#start()) + +### dequeueInputBuffer +- [dequeueInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#dequeueInputBuffer(long)) + +### queueInputBuffer +- [queueInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#queueInputBuffer(int,%20int,%20int,%20long,%20int)) + +### getInputBuffer +- [getInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#getInputBuffer(int)) + +### dequeueOutputBuffer +- [dequeueOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#dequeueOutputBuffer(android.media.MediaCodec.BufferInfo,%20long)) + +### getOutputBuffer +- [getOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#getOutputBuffer(int)) + +### releaseOutputBuffer +- [releaseOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#releaseOutputBuffer(int,%20boolean)) + +### stop +- [stop](https://developer.android.com/reference/android/media/MediaCodec#stop()) + +### release +- [release](https://developer.android.com/reference/android/media/MediaCodec#release()) + +## 使用 +1. 根據需求使用createEncoderByType或是createDecoderByType建立codec。以下以encode為例。 +2. 呼叫configure,傳入相應的MediaFormat。 +3. 呼叫start,開始encode。 +4. 建立一個迴圈,不斷的傳入要encode的buffer,也不斷的拿出已經encode的buffer。 +5. 在迴圈內,要傳入的buffer處理方法: + 1. 呼叫dequeueInputBuffer,試探是否有能用的buffer,如果有,回傳值將大於等於0(>= 0)。這裡假設回傳值的變數叫做index。 + 2. 如果index合法,用`inputBuffer = queueInputBuffer(index)`來取得可用的buffer。這裡假設buffer的變數叫做inputBuffer。 + 3. 將要encode的資料copy到inputBuffer。 +6. 在迴圈內,要取得已經encode buffer的方法: + 1. 呼叫dequeueOutputBuffer,試探是否有encoded buffer,如果有,回傳值將大於等於0(>= 0)。這裡假設回傳值的變數叫做index。 + 2. 如果index合法,用`outputBuffer = getOutputBuffer(index)`來取得可用的buffer。這裡假設buffer的變數叫做outputBuffer。 + 3. outputBuffer 就是已經 encode 好的,就看你怎麼處理。 + 4. 重要!呼叫 releaseOutputBuffer 來回收剛剛那一塊 buffer。 + +Psuedo code 如下: +```kotlin +while (true) + // send buffer to encode + index = dequeueInputBuffer() + if (index >= 0) + inputBuffer = queueInputBuffer(index) + copy(inputBuffer, srcBuffer) + // Get encoded buffer + index = dequeueOutputBuffer() + if (index >= 0) + outputBuffer = getOutputBuffer(index) + releaseOutputBuffer(index) +``` + +## 參考資料 +- [Android音视频之使用MediaCodec编解码AAC - 简书](https://www.jianshu.com/p/14daab91b951) +- [MultiMediaLearning/app/src/main/java/com/richie/multimedialearning/mediacodec at master · isuperqiang/MultiMediaLearning](https://github.com/isuperqiang/MultiMediaLearning/tree/master/app/src/main/java/com/richie/multimedialearning/mediacodec) +- [初识MediaCodec - 知乎](https://zhuanlan.zhihu.com/p/45224834) +- [MediaCodec的使用介绍 - 简书](https://www.jianshu.com/p/f5a1c9318524) +- [Android原生编解码接口MediaCodec详解 - 掘金](https://juejin.cn/post/7086297619764346887) +- [AndroidMediaCodecDemo/AudioDecoder.kt at main · king-ma1993/AndroidMediaCodecDemo](https://github.com/king-ma1993/AndroidMediaCodecDemo/blob/main/app/src/main/java/com/myl/mediacodedemo/decode/audio/AudioDecoder.kt) +- [Android使用系统API进行音视频编码_key_max_input_size_blueberry_mu的博客-CSDN博客](https://blog.csdn.net/a992036795/article/details/54286654) +- [MediaCodec 完成PCM编码成AAC - 知乎](https://zhuanlan.zhihu.com/p/564759685) +- [MediaCodec 同步方式完成AAC硬解成PCM - 知乎](https://zhuanlan.zhihu.com/p/564734700) \ No newline at end of file diff --git a/04. Programming/Kotlin/AtomicBoolean.md b/04. Programming/Kotlin/AtomicBoolean.md index 1f114fd..ea0291e 100644 --- a/04. Programming/Kotlin/AtomicBoolean.md +++ b/04. Programming/Kotlin/AtomicBoolean.md @@ -18,7 +18,42 @@ init.set(true) // 將 init 設為 true ## 其他function ### compareAndExchange - +- [compareAndExchange](https://developer.android.com/reference/java/util/concurrent/atomic/AtomicBoolean#compareAndExchange(boolean,%20boolean)) +```java +public final boolean compareAndExchange ( + boolean expectedValue, + boolean newValue) +``` +如果目前的值跟`expectedValue`相等,回傳目前值,並將目前值設為`newValue`。 +如果目前的值跟`expectedValue`不相等,回傳目前值,不做任何設定。 ### compareAndSet +- [compareAndSet](https://developer.android.com/reference/java/util/concurrent/atomic/AtomicBoolean#compareAndSet(boolean,%20boolean)) +```java +public final boolean compareAndSet ( + boolean expectedValue, + boolean newValue) +``` +如果目前的值跟`expectedValue`相等,return `true`,並將目前值設為`newValue`。 +如果目前的值跟`expectedValue`不相等,return `false`。 +## 用途 +一般而言,`set` 與 `get` 已經夠用,但如果需要讀值並設定一個新值的話,那就需要 `compareAndSet` 或是 `compareAndExchange`,不然就需要另一個 `mutex` 來達到同樣效果。 +假設一個情況,假設目前是 `false` 的情況下,我們可以存取某些資源,所以也要把值設為 `true`,用 `mutex` 的作法如下: +```kotlin +mutex.lock() +if (useable.get()) { + useable.set(false) + // Do something +} +mutex.unlock() +``` +改用 `compareAndSet` 就是: +```kotlin +if (useable.compareAndSet(false, true)) { + // Do something +} +``` + +## 資料 +- [java - compareandexchange() vs compareandset() of Atomic-Integer - Stack Overflow](https://stackoverflow.com/questions/60648557/compareandexchange-vs-compareandset-of-atomic-integer) \ No newline at end of file diff --git a/attachments/android_mediacodec_flow.png b/attachments/android_mediacodec_flow.png new file mode 100644 index 0000000..ddc4a8f Binary files /dev/null and b/attachments/android_mediacodec_flow.png differ diff --git a/attachments/android_mediacodec_life_cycle.png b/attachments/android_mediacodec_life_cycle.png new file mode 100644 index 0000000..ffc6d69 Binary files /dev/null and b/attachments/android_mediacodec_life_cycle.png differ