国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android音視頻-MediaCodec

這篇具有很好參考價值的文章主要介紹了Android音視頻-MediaCodec。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

原文:https://mp.weixin.qq.com/s?__biz=MzU3NTA3MDU1OQ==&mid=2247484865&idx=1&sn=174b8ca702466e83e72c7115d91b06ea&chksm=fd298df1ca5e04e7b2df9dc9f21e5cfe3e910204c905d8605f648ce6f6404432a83ae52a23a3&scene=178&cur_album_id=1638784435628064770#rd

MediaCodec 支持處理三種數(shù)據(jù)類型,分別是壓縮數(shù)據(jù)(compressed data)、原始音頻數(shù)據(jù)(raw audio data)、原始視頻數(shù)據(jù)(raw video data),可以使用 ByteBuffer 處理這三種數(shù)據(jù),也就是后文中提到的緩沖區(qū), 可以使用 Surface 來提高編解碼器性能,可以通過 ImageReader 訪問原始視頻幀,不能直接訪問原始視頻數(shù)據(jù),通過 Image 進而獲取到與之對應的 YUV 數(shù)據(jù)等其他信息。

壓縮緩沖區(qū):用于解碼器的輸入緩沖區(qū)和用于編碼器的輸出緩沖區(qū)會包含 MediaFormat 的 KEY_MIME 對應類型的壓縮數(shù)據(jù),對于視頻類型,通常是單個壓縮視頻幀,對于音頻數(shù)據(jù),這通常是一個編碼的音頻段,通常包含幾毫秒的音頻,因格式類型而定。

原始視頻緩沖區(qū):

格式:在 ByteBuffer 模式下,視頻緩沖區(qū)根據(jù)其 MediaFormat 的 KEY_COLOR_FORMAT 設置的值進行布局,可以從通過 MediaCodecInfo 相關方法獲取設備受支持的顏色格式,視頻編解碼器可能支持三種顏色格式:

native raw video format:原始原始視頻格式,由CodecCapabilities 的 COLOR_FormatSurface 常量標記,可以與輸入或輸出Surface一起使用。

flexible YUV buffers:靈活的 YUV 緩沖區(qū),如 CodecCapabilities 的 COLOR_FormatYUV420Flexible 常量對應的顏色格式,可以通過 getInput、OutputImage 等于與輸入、輸出 Surface 以及 ByteBuffer 模式一起使用。

other specific formats:其他特定格式:通常僅在 ByteBuffer 模式下支持這些格式, 某些顏色格式是特定于供應商的,其他在均在 CodecCapabilities 中定義。

自 Android 5.1 開始,所有視頻編解碼器均支持靈活的 YUV 4:2:0 緩沖區(qū)。
視頻幀大小于緩沖區(qū)幀大小關系:
編解碼器的MediaFormat#KEY_WIDTH 和 MediaFormat#KEY_HEIGHT 鍵指定視頻幀的大小,在大多數(shù)情況下,視頻僅占據(jù)視頻幀的一部分,具體表示如下:

Android音視頻-MediaCodec

需要使用以下鍵從輸出格式獲取原始輸出圖像的裁剪矩形,如果輸出格式中不存在這些鍵,則視頻將占據(jù)整個視頻幀,在使用任何 MediaFormat#KEY_ROTATION 之前,也就是在設置旋轉之前,可以使用下面的方式計算視頻幀的大小,參考如下:

MediaFormat format = decoder.getOutputFormat();
int width = format.getInteger(MediaFormat.KEY_WIDTH);
if (format.containsKey("crop-left") && format.containsKey("crop-right")) {
    width = format.getInteger("crop-right") + 1 - format.getInteger("crop-left");
}
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
if (format.containsKey("crop-top") && format.containsKey("crop-bottom")) {
   height = format.getInteger("crop-bottom") + 1 - format.getInteger("crop-top");
}

MediaCodec編解碼的流程

客戶端首先從MediaCodec獲取一個空的輸入緩沖區(qū),用于填充要編碼或解碼的數(shù)據(jù),
然后通過其它借口填充數(shù)據(jù),比如解碼視頻用的MediaExtractor.readSampleData(inputBuffer, 0)
再將填充數(shù)據(jù)的輸入緩沖區(qū)送到 MediaCodec
MediaCodec處理數(shù)據(jù),就是編碼或者解碼
MediaCodec處理完數(shù)據(jù)后將數(shù)據(jù)填充到緩沖區(qū),然后釋放輸入緩沖區(qū)
最后客戶端獲取已經(jīng)編碼或解碼的輸出緩沖區(qū),使用完畢后釋放輸出緩沖區(qū),

其編解碼的流程示意圖如下:
Android音視頻-MediaCodec

MediaCodec生命周期

MediaCodec 有三種狀態(tài),分別是執(zhí)行(Executing)、停止(Stopped)和釋放(Released),其中執(zhí)行和停止分別有三個子狀態(tài),執(zhí)行的三個字狀態(tài)分別是 Flushed、Running 和 Stream-of-Stream,停止的三個子狀態(tài)分別是 Uninitialized、Configured 和 Error,MediaCodec 生命周期示意圖如下:

Android音視頻-MediaCodec
如上圖所示,三種狀態(tài)的切換都是由 start、stop、reset、release 等觸發(fā),根據(jù) MediaCodec 處理數(shù)據(jù)方式的不同,其生命周期會略有不同,如在異步模式下 start 之后立即進入 Running 子狀態(tài),如果已經(jīng)處于 Flushed 子狀態(tài),則需再次調用 start 進入 Running 子狀態(tài),下面是各個子狀態(tài)切換對應的關鍵 API 如下:
停止狀態(tài)(Stopped)

停止狀態(tài)(Stopped)
 // 創(chuàng)建MediaCodec進入Uninitialized子狀態(tài)
public static MediaCodec createByCodecName (String name)
public static MediaCodec createEncoderByType (String type)
public static MediaCodec createDecoderByType (String type)
// 配置MediaCodec進入Configured子狀態(tài),crypto和descrambler會在后文中進行說明
public void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags)
public void configure(MediaFormat format, @Nullable Surface surface,int flags, MediaDescrambler descrambler)
// Error
// 編解碼過程中遇到錯誤進入Error子狀態(tài)
配置成功之后進入 執(zhí)行狀態(tài)(Executing) 然后start

// start之后立即進入Flushed子狀態(tài)
public final void start()

// 客戶端獲取第一個輸入緩沖區(qū)索引的時候進入Running子狀態(tài)
public int dequeueInputBuffer (long timeoutUs)

// 此時MediaCodec將不接受其他輸入緩沖區(qū),但會生成輸出緩沖區(qū)
// 將填滿數(shù)據(jù)的inputBuffer提交到編碼隊列 也是run
public void queueInputBuffer (int index, int offset, int size, long presentationTimeU)

// 遇到結束符,輸入緩沖區(qū)與流結束標記排隊時,編解碼器將轉換為End-of-Stream子狀態(tài)

釋放狀態(tài)(Released)

1// 編解碼完成結束后釋放MediaCodec進入釋放狀態(tài)(Released)
2public void release ()

MediaCodec的創(chuàng)建

前面已經(jīng)提到過當創(chuàng)建 MediaCodec 的時候進入Uninitialized 子狀態(tài),其創(chuàng)建方式如下:

 1// 創(chuàng)建MediaCodec
2public static MediaCodec createByCodecName (String name)
3public static MediaCodec createEncoderByType (String type)
4public static MediaCodec createDecoderByType (String type)
5

使用 createByCodecName 時可以借助 MediaCodecList 獲取支持的編解碼器,下面是獲取指定 MIME 類型的編碼器:

 1/**
 2 * 查詢指定MIME類型的編碼器
 3 */
 4fun selectCodec(mimeType: String): MediaCodecInfo? {
 5    val mediaCodecList = MediaCodecList(MediaCodecList.REGULAR_CODECS)
 6    val codeInfos = mediaCodecList.codecInfos
 7    for (codeInfo in codeInfos) {
 8        if (!codeInfo.isEncoder) continue
 9        val types = codeInfo.supportedTypes
10        for (type in types) {
11            if (type.equals(mimeType, true)) {
12                return codeInfo
13            }
14        }
15    }
16    return null
17}

當然 MediaCodecList 也提供了相應的獲取編解碼器的方法,如下:

1// 獲取指定格式的編碼器
2public String findEncoderForFormat (MediaFormat format)
3// 獲取指定格式的解碼器
4public String findDecoderForFormat (MediaFormat format)
5

對于上述方法中的參數(shù) MediaFormat 格式中不能包含任何幀率的設置,如果已經(jīng)設置了幀率需要將其清除再使用。

上面提到了 MediaCodecList,這里簡單說一下,使用 MediaCodecList 可以方便的列出當前設備支持的所有的編解碼器,創(chuàng)建 MediaCodec 的時候要選擇當前格式支持的編解碼器,也就是選擇的編解碼器需支持對應的 MediaFormat,每個編解碼器都被包裝成一個 MediaCodecInfo 對象,據(jù)此可以查看該編碼器的一些特性,比如是否支持硬件加速、是軟解還是硬解編解碼器等,常用的簡單如下

 1// 是否軟解
 2public boolean isSoftwareOnly ()
 3// 是Android平臺提供(false)還是廠商提供(true)的編解碼器
 4public boolean isVendor ()
 5// 是否支持硬件加速
 6public boolean isHardwareAccelerated ()
 7// 是編碼器還是解碼器
 8public boolean isEncoder ()
 9// 獲取當前編解碼器支持的合適
10public String[] getSupportedTypes ()
11// ...

軟解和硬解應該是音視頻開發(fā)中必須掌握的,當使用 MediaCodec 的時候不能說全是硬解,到底使用硬解還是軟解還是要看使用的編碼器,一般廠商提供的編解碼器都是硬解編解碼器,比如高通(qcom)等,一般如系統(tǒng)提供的則是軟解編解碼器,如帶有 android 字樣的編解碼器,下面是本人(MI 10 Pro)自己手機的部分編解碼器:

 1// 硬解編解碼器
 2OMX.qcom.video.encoder.heic
 3OMX.qcom.video.decoder.avc
 4OMX.qcom.video.decoder.avc.secure
 5OMX.qcom.video.decoder.mpeg2
 6OMX.google.gsm.decoder
 7OMX.qti.video.decoder.h263sw
 8c2.qti.avc.decoder
 9...
10// 軟解編解碼器
11c2.android.aac.decoder
12c2.android.aac.decoder
13c2.android.aac.encoder
14c2.android.aac.encoder
15c2.android.amrnb.decoder
16c2.android.amrnb.decoder
17...

MediaCodec初始化

創(chuàng)建 MediaCodec 之后進入 Uninitialized 子狀態(tài),此時需要對其進行一些設置如指定 MediaFormat、如果使用的是異步處理數(shù)據(jù)的方式,在 configure 之前要設置 MediaCodec.Callback,關鍵 API 如下:

 1// 1. MediaFormat
 2// 創(chuàng)建MediaFormat
 3public static final MediaFormat createVideoFormat(String mime,int width,int height)
 4// 開啟或關閉功能,具體參見MediaCodeInfo.CodecCapabilities
 5public void setFeatureEnabled(@NonNull String feature, boolean enabled)
 6// 參數(shù)設置
 7public final void setInteger(String name, int value)
 8
// 2. setCallback
10// 如果使用的是異步處理數(shù)據(jù)的方式,在configure 之前要設置 MediaCodec.Callback
11public void setCallback (MediaCodec.Callback cb)
12public void setCallback (MediaCodec.Callback cb, Handler handler)
13
14// 3. 配置
15public void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags)
16public void configure(MediaFormat format, @Nullable Surface surface,int flags, MediaDescrambler descrambler)
  • 此外某些特定格式比如 AAC 音頻以及 MPEG4、H.264、H.265 視頻格式,這些格式包含一些用于 MediaCodec 的初始化特定的數(shù)據(jù),當解碼處理這些壓縮格式時,必須在 start 之后且在任何幀數(shù)據(jù)處理之前將這些特定數(shù)據(jù)提交給 MediaCodec,即在對 queueInputBuffer 的調用中使用標志 BUFFER_FLAG_CODEC_CONFIG 標記此類數(shù)據(jù),這些特定的數(shù)據(jù)也可以通過 MediaFormat 設置 ByteBuffer 的方式進行配置,如下:
1// csd-0、csd-1、csd-2同理
2val bytes = byteArrayOf(0x00.toByte(), 0x01.toByte())
3mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(bytes))

其中 csd-0、csd-1 這些鍵可以從 MediaExtractor#getTrackFormat 獲取的MediaFormat中獲取,這些特定的數(shù)據(jù)會在start 時自動提交給 MediaCodec,無需直接提交此數(shù)據(jù),如果在輸出緩沖區(qū)或格式更改之前調用了 flush,則會丟失提交的特定數(shù)據(jù),就需要在 queueInputBuffer 的調用中使用標志 BUFFER_FLAG_CODEC_CONFIG 標記這類數(shù)據(jù)。
Android 使用以下特定于編解碼器的數(shù)據(jù)緩沖區(qū),為了正確配置 MediaMuxer 軌道,還需要將它們設置為軌道格式,每個參數(shù)集和標有(*)的編解碼器專用數(shù)據(jù)部分必須以“ \ x00 \ x00 \ x00 \ x01”的起始代碼開頭,參考如下:
Android音視頻-MediaCodec
編碼器在收到這些信息后將會同樣輸出帶有BUFFER_FLAG_CODEC_CONFIG標記的 outputbuffer,此時這些數(shù)據(jù)就是特定數(shù)據(jù),不是媒體數(shù)據(jù)。

MediaCodec數(shù)據(jù)處理方式

每個創(chuàng)建已經(jīng)創(chuàng)建的編解碼器都維護一組輸入緩沖區(qū),有兩種處理數(shù)據(jù)的方式,同步和異步方式,根據(jù) API 版本不同有所區(qū)別,在 API 21 也就是從 Android5.0 開始,推薦使用 ButeBuffer 的方式進行數(shù)據(jù)的處理。

MediaCodec,也就是編解碼器的數(shù)據(jù)處理,主要是獲取輸入、輸出緩沖區(qū)、提交數(shù)據(jù)給編解碼器、釋放輸出緩沖區(qū)這幾個過程,同步方式和異步方式的不同點在于輸入緩沖區(qū)和輸出緩沖區(qū)的其關鍵 API 如下:

 1// 獲取輸入緩沖區(qū)(同步)
 2public int dequeueInputBuffer (long timeoutUs)
 3public ByteBuffer getInputBuffer (int index)
 4// 獲取輸出緩沖區(qū)(同步)
 5public int dequeueOutputBuffer (MediaCodec.BufferInfo info, long timeoutUs)
 6public ByteBuffer getOutputBuffer (int index)
 7// 輸入、輸出緩沖區(qū)索引從MediaCodec.Callback的回調中獲取,在獲取對應的輸入、輸出緩沖區(qū)(異步)
 8public void setCallback (MediaCodec.Callback cb)
 9public void setCallback (MediaCodec.Callback cb, Handler handler)
10// 提交數(shù)據(jù)
11public void queueInputBuffer (int index, int offset, int size, long presentationTimeUs, int flags)
12public void queueSecureInputBuffer (int index, int offset, MediaCodec.CryptoInfo info, long presentationTimeUs, int flags)
13// 釋放輸出緩沖區(qū)
14public void releaseOutputBuffer (int index, boolean render)
15public void releaseOutputBuffer (int index, long renderTimestampNs)
16

處理數(shù)據(jù)的結束

當要處理的數(shù)據(jù)結束時(End-of-stream),需要標記流的結束,可以在最后一個有效的輸入緩沖區(qū)上使用 queueInputBuffer 提交數(shù)據(jù)的時候指定 flags 為 BUFFER_FLAG_END_OF_STREAM 標記其結束,也可以在最后一個有效輸入緩沖區(qū)之后提交一個空的設置了流結束標志的輸入緩沖區(qū)來標記其結束,此時不能夠再提交輸入緩沖區(qū),除非編解碼器被 flush、stop、restart,輸出緩沖區(qū)繼續(xù)返回直到最終通過在 dequeueOutputBuffer 或通過 Callback#onOutputBufferAvailable 返回的 BufferInfo 中指定相同的流結束標志,最終通知輸出流結束為止。
如果使用了一個輸入 Surface 作為編解碼器的輸入,此時沒有可訪問的輸入緩沖區(qū),輸入緩沖區(qū)會自動從這個 Surface 提交給編解碼器,相當于省略了輸入的這個過程,這個輸入 Surface 可由 createInputSurface 方法創(chuàng)建,此時調用 signalEndOfInputStream 將發(fā)送流結束的信號,調用后,輸入表面將立即停止向編解碼器提交數(shù)據(jù),關鍵 API 如下:
1// 創(chuàng)建輸入Surface,需在configure之后、start之前調用
2public Surface createInputSurface ()
3// 設置輸入Surface
4public void setInputSurface (Surface surface)
5// 發(fā)送流結束的信號
6public void signalEndOfInputStream ()
7
同理如果使用了輸出 Surface,則與之相關的輸出緩沖區(qū)的相關功能將會被代替,可以通過 setOutputSurface 設置一個 Surface 作為編解碼器的輸出,可以選擇是否在輸出 Surface 上渲染每一個輸出緩沖區(qū),關鍵 API 如下:
1// 設置輸出Surface
2public void setOutputSurface (Surface surface)
3// false表示不渲染這個buffer,true表示使用默認的時間戳渲染這個buffer
4public void releaseOutputBuffer (int index, boolean render)
5// 使用指定的時間戳渲染這個buffer
6public void releaseOutputBuffer (int index, long renderTimestampNs)

自適應播放支持

當 MediaCodec 作為視頻解碼器的時候,可以通過如下方式檢查解碼器是否支持自適應播放,也就是此時解碼器是否支持無縫的分辨率修改:
1// 是否支持某項功能,CodecCapabilities#FEATURE_AdaptivePlayback對應對應自適應播放支持
2public boolean isFeatureSupported (String name)
3
此時只有在將解碼器配置在 Surface 上解碼時,自適應播放的功能才會被激活,視頻解碼時當 strat 或 flush 調用后,只有關鍵幀(key-frame)才能完全獨立解碼,也就是通常說的 I 幀,其他幀都是據(jù)此來解碼的,不同格式對應關鍵幀如下:
圖片
不同的解碼器對自適應播放的支持能力不同,其 seek 操作后處理也是不同,這部分內容暫時留到后續(xù)具體實踐后再做整理。

seeking和自適應播放支持
無論是否支持并配置為自適應播放,視頻解碼器(以及一些壓縮數(shù)據(jù)的編碼器)在seek和格式更改的行為都不同??梢酝ㄟ^CodecCapatilities.isFeatureSupported(String)檢查解碼器是否支持自適應播放。視頻解碼器的自適應播放只有在將codec配置到Surface上時,才會被激活。

流邊界和關鍵幀
重要的是,在start()或者flush()后輸入數(shù)據(jù)要在合適的流邊界開始:第一幀必須是關鍵幀。
關鍵幀可以通過自身被完全解碼(大多數(shù)codec的I幀),并且關鍵幀之后沒有幀要顯示指的是關鍵幀之前的幀。
下表對不同視頻格式合適的關鍵幀進行了總結:

不支持自適應播放的解碼器(包括不解碼到Surface)
為了開始解碼與之前提交數(shù)據(jù)不相鄰的數(shù)據(jù),必須flush解碼器。由于所有的輸出buffer在flush時被立即撤銷,所以需要首先發(fā)送信號,等到end-of-stream標志時再flush。重要的是,刷新后的輸入數(shù)據(jù)在合適的流邊界/關鍵幀開始。

注意,提交數(shù)據(jù)的格式在flush后必須不能更改,flush() 不支持不連續(xù)的格式。對于這種情況,一個完整的stop() - configure(…) - start() 的循環(huán)的必要的。
同時注意,如果你在start()后flush codec太頻繁 - 一般來說,在首次output buffer或output format變更被接收到時 - 你需要重新提交codec-specific-data到codec??梢圆榭瓷厦骊P于 codec-specific-data 一塊的介紹。

支持并配置自適應播放的解碼器
為了開始解碼與之前提交數(shù)據(jù)不相鄰的數(shù)據(jù)(如在seek后),不需要flush解碼器。這樣,輸入數(shù)據(jù)是不連續(xù)的,必須從一個合適的流邊界/關鍵幀開始。

對于某些視頻格式,即H.264,H.265,VP8和VP9,也可以改變畫面大小或配置中間流。為此,須將整個新的codec-specific configuration data與關鍵幀一起打包到單個buffer(包括任何起始代碼)中,并將其作為常規(guī)輸入buffer提交。
在圖像大小更改發(fā)生之后及在返回新尺寸的任何幀之前,可以從dequeueOutputBuffer或onOutputFormatChanged回調中獲得INFO_OUTPUT_FORMAT_CHANGED返回值。

就像codec-specific configuration data一樣,在更改圖片大小后不久,調用flush()時要小心,如果沒有收到圖片尺寸更改的確認,需要重新請求圖片大小。

MediaCodec的異常處理

關于 MediaCodec 使用過程中的異常處理,這里提一下 CodecException 異常,一般是由編解碼器內部異常導致的,比如媒體內容損壞、硬件故障、資源耗盡等,可以通過如下方法判斷以做進一步的處理:
1// true表示可以通過stop、configure、start來恢復
2public boolean isRecoverable ()
3// true表示暫時性問題,編碼或解碼操作會在后續(xù)重試進行
4public boolean isTransient ()
如果 isRecoverable 和 isTransient 都是返回 false,則需要通過 reset 或 release 操作釋放資源后重新工作,兩者不可能同時返回 true。關于 MediaCodec 的介紹到此為止。

ImageReader

Imagee reader 類允許應用程序直接訪問渲染到 Surface 中的圖像數(shù)據(jù)。
多個 Android 媒體 API 類接受 Surface 對象作為渲染的目標,包括 MediaPlayer、 MediaCodec、 CameraDevice、 ImageWriter 和 RenderScript 分配。每個源使用的圖像大小和格式各不相同,應該在針對特定 API 的文檔中進行檢查。比如 mediaCodec.configure(videoFormat, imageReader.getSurface(), null, 0);
將imageReader的surface表面?zhèn)鬟f給解碼器,作為解碼數(shù)據(jù)輸出位置。

官方文檔寫的:有效的大小和格式取決于圖像數(shù)據(jù)的來源。意思應該是通過ImageReader設置的大小和格式無效??

圖像數(shù)據(jù)封裝在 Image 對象中,可以同時訪問多個這樣的對象,最多可以訪問 maxImages 個對象,maxImages構造函數(shù)參數(shù)指定,應該盡量小,減少內存消耗。

通過 Surface 發(fā)送到 ImageReader 的新映像將排隊,直到通過 acquireLatestImage ()或 acquirenextage ()調用訪問為止。由于內存限制,如果 image reader 無法獲取并釋放 Images,則圖像源最終會在嘗試將 Images 渲染到 Surface 時停止或丟棄 Images

從ImageReader的隊列中獲取下一幅圖像。如果沒有可用的新圖像,則返回null。

構造方法

newInstance
為所需大小、格式和消費者使用標志的圖像創(chuàng)建新的讀取器。
maxImages參數(shù)確定可以同時從ImageReader獲取的圖像對象的最大數(shù)量。請求更多緩沖區(qū)會占用更多內存,因此只使用用例所需的最小數(shù)量是很重要的。
有效的大小和格式取決于圖像數(shù)據(jù)的來源。
**format and usage flag組合描述消費者端點將如何使用緩沖區(qū)。**例如,如果應用程序打算將圖像發(fā)送到MediaCodec或MediaRecorder進行硬件視頻編碼,則格式和使用標志組合需要是私有和硬件緩沖#使用#視頻#編碼。當ImageReader對象以有效大小和此類格式/使用標志組合創(chuàng)建時,應用程序可以將圖像發(fā)送到ImageWriter,該ImageWriter使用MediaCodec或MediaRecorder提供的輸入面創(chuàng)建。
如果格式是私有的,則創(chuàng)建的ImageReader將生成應用程序無法直接訪問的圖像。應用程序仍然可以從該ImageReader獲取圖像,并將其發(fā)送到相機進行重新處理,或通過ImageWriter接口發(fā)送到MediaCodec/MediaRecorder進行硬件視頻編碼。但是,getPlanes()將為私有格式的圖像返回一個空數(shù)組。應用程序可以通過調用getImageFormat()檢查現(xiàn)有讀取器的格式。
與使用其他格式(如YUV_420_888)的圖像閱讀器相比,當應用程序不需要訪問圖像數(shù)據(jù)時,使用專用格式的圖像閱讀器更高效。
請注意,并非ImageReader支持所有格式和使用標志組合。下面是ImageReader支持的組合(假設消費者端點支持這種圖像消費,例如硬件視頻編碼)。

acquireNextImage()
建議使用acquireNextImage()進行批處理/后臺處理。不正確地使用此功能可能會導致圖像顯示的延遲越來越大,然后出現(xiàn)完全停滯,似乎沒有新圖像出現(xiàn)。

如果已使用acquireNextImage()或acquireLatestImage()獲取了最大值,則此操作將因引發(fā)非法狀態(tài)異常而失敗。特別是,如果acquireNextImage()或acquireLatestImage()調用的序列大于maxImages,而不調用圖像#介于兩者之間,則會耗盡底層隊列。此時,將拋出IllegalStateException,直到使用Image#close發(fā)布更多圖像。

getSurface
公共表面getSurface()
獲取一個可用于為該ImageReader生成圖像的表面。
在將有效的圖像數(shù)據(jù)渲染到此曲面之前,acquireNextImage()方法將返回null。只有一個源可以同時向該曲面生成數(shù)據(jù),盡管一旦第一個源與曲面斷開連接,同一個曲面可以通過不同的API重用。
請注意,保持此方法返回的曲面對象不足以防止其父ImageReader被回收。從這個意義上說,曲面就像是對提供它的ImageReader的弱引用。文章來源地址http://www.zghlxwxcb.cn/news/detail-400732.html

到了這里,關于Android音視頻-MediaCodec的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 5G時代下,Android音視頻強勢崛起,我們該如何快速入門音視頻技術?

    5G時代下,Android音視頻強勢崛起,我們該如何快速入門音視頻技術?

    作為Android開發(fā)者的我們到底應不應該上音視頻這條船? 接下來一起分析下。 大趨勢 從未來的大趨勢來看,隨著5G時代的到來,音視頻慢慢變成人們日常生活中的必需品。除了在線教育、音視頻會議、即時通訊這些必須使用音視頻技術的產品外,其它的產品也需要加入音頻、

    2024年04月15日
    瀏覽(28)
  • Android音視頻編碼(2)

    Android音視頻編碼(2)

    Android本身提供了音視頻編解碼工具,很多時候是不需要第三方工具的,比如 ffmpeg , OpenCV 等,在android中引入第三庫比較復雜,在Android音視頻編碼中介紹了如何引入第三方庫libpng來進行進行圖片處理,同時引入這些第三方庫,是程序結構變得復雜。 本文介紹的音視頻編解碼利

    2024年01月17日
    瀏覽(22)
  • Android 音視頻開發(fā) - VideoView

    本篇文章主要介紹下Android 中的VideoView. VideoView是一個用于播放視頻的視圖組件,可以方便地在應用程序中播放本地或網(wǎng)絡上的視頻文件。 VideoView可以直接在布局文件中使用,也可以在代碼中動態(tài)創(chuàng)建。 它封裝了MediaPlayer和SurfaceView,提供了簡單的接口來控制視頻的播放和顯示

    2024年04月08日
    瀏覽(27)
  • Android音視頻: 引入FFmpeg

    Android音視頻: 引入FFmpeg

    本文你可以了解到 本文將介紹如何將上一篇文章編譯出來的? FFmpeg so ?庫,引入到? Android ?工程中,并驗證? so ?是否可以正常使用。 一、開啟 Android 原生 C/C++ 支持 在過去,通常使用? makefile ?的方式在項目中引入? C/C++ ?代碼支持,隨著? Android Studio ?的普及, makefile ?的

    2024年02月02日
    瀏覽(27)
  • Android之 集成音視頻通話

    Android之 集成音視頻通話

    一,背景 1.1 最近接收一個即時通訊二開項目,即時通訊部分用的XMPP協(xié)議,音視頻則是集成的國外的開源免費庫jitsi-meet-sdk-2.4.0-4.aar,是基于WebRTC的開源框架。但客戶想要微信那種頁面的排版,后來經(jīng)研究jitsi是不能修改UI的,UI部分是用混合框架ReactNative寫的,這樣難度就大了

    2024年02月12日
    瀏覽(32)
  • Android音視頻之協(xié)議介紹

    Android音視頻之協(xié)議介紹

    本文對音視頻的協(xié)議起源做詳細介紹,學習之后可以加深對音視頻知識的了解。 這里的音視頻不僅針對Android平臺,其他平臺也通用。 一般是指以某種格式封裝了音視頻數(shù)據(jù)的文件 常見的音頻格式:mp3、wma、avi、rm、rmvb、flv、mpg、mov、mkv等。 常見的視頻格式:rmvb、rm、wmv、

    2023年04月19日
    瀏覽(21)
  • Android音視頻開發(fā) - MediaMetadataRetriever 相關

    MediaMetadataRetriever 是android中用于從媒體文件中提取元數(shù)據(jù)新的類. 可以獲取音頻,視頻和圖像文件的各種信息,如時長,標題,封面等. 需要申請 讀寫權限 . 這里我使用的是本地路徑, 需要注意的是如果路徑文件不存在,會拋出 IllegalArgumentException,具體的源碼如下: 根據(jù)keyCode返回keyC

    2024年04月08日
    瀏覽(31)
  • Android 音視頻開發(fā)—MediaPlayer音頻與視頻的播放介紹

    Android 音視頻開發(fā)—MediaPlayer音頻與視頻的播放介紹

    Android多媒體中的——MediaPlayer,我們可以通過這個API來播放音頻和視頻該類是Androd多媒體框架中的一個重要組件,通過該類,我們可以以最小的步驟來獲取,解碼和播放音視頻。 它支持三種不同的媒體來源: 本地資源 內部的URI,比如你可以通過ContentResolver來獲取 外部URL(流

    2024年02月10日
    瀏覽(27)
  • Android音視頻——OpenMAX (OMX)框架

    Android音視頻——OpenMAX (OMX)框架

    本文分為兩個部分進行講解 Codec 部分中的 AwesomePlayer 到 OMX 服務 前面介紹了NuPlayer最終解碼都會到達OMX框架,也就是 OpenMAX框架,本文開始分析編解碼部分中的AwesomePlayer到OMX服務過程,也就是開啟OpenMAX準備相關內容。Android系統(tǒng)中用OpenMAX來做編解碼,Android向上抽象了一 層O

    2023年04月09日
    瀏覽(32)
  • Android音視頻開發(fā)實戰(zhàn)02-Jni

    Android音視頻開發(fā)實戰(zhàn)02-Jni

    JNI是Java Native Interface的縮寫,是Java提供的一種機制,用于在Java代碼中調用本地(C/C++)代碼。它允許Java代碼與本地代碼進行交互,通過JNI,Java應用程序可以調用一些原生庫或者操作系統(tǒng)API,以獲取更好的性能和更強的功能支持。 使用JNI需要編寫一些Native方法,并將其實現(xiàn)在

    2024年02月11日
    瀏覽(30)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包