vault backup: 2023-03-19 22:30:40

This commit is contained in:
2023-03-19 22:30:40 +08:00
parent bf0fb5dded
commit b1f5dea040
6 changed files with 182 additions and 22 deletions

View File

@@ -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"
]
}

View File

@@ -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)

View File

@@ -0,0 +1,104 @@
## 一般流程
1. 使用者從MediaCodec請求一個空的輸入bufferByteBuffer填充滿數據後將它傳遞給MediaCodec處理。
2. MediaCodec處理完這些數據並將處理結果輸出至一個空的輸出bufferByteBuffer中。
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. ErrorMediaCodec遇到錯誤時進入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)

View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB