MediaCodec 類別
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
MediaCodec 類別可用來存取低階媒體編解碼器 i。
[Android.Runtime.Register("android/media/MediaCodec", DoNotGenerateAcw=true)]
public sealed class MediaCodec : Java.Lang.Object
[<Android.Runtime.Register("android/media/MediaCodec", DoNotGenerateAcw=true)>]
type MediaCodec = class
inherit Object
- 繼承
- 屬性
備註
MediaCodec 類別可用來存取低階媒體編解碼器,例如編碼器/譯碼器元件。 它是 Android 低階多媒體支援基礎結構的一部分, (通常與 、MediaSync
、MediaCrypto
MediaDrm
MediaMuxer
Image
、 Surface
和 AudioTrack
.) 搭配使用MediaExtractor
<center><img src=“../../../images/media/mediacodec_buffers.svg“ style=”width: 540px;height: 205px“ alt=”MediaCodec 緩衝區流程圖“></center>
在廣泛方面,編解碼器會處理輸入數據以產生輸出數據。 它會以異步方式處理數據,並使用一組輸入和輸出緩衝區。 在簡單層級,您會要求 (或接收) 空的輸入緩衝區、填滿數據,並將它傳送至編解碼器進行處理。 編解碼器會使用數據,並將其轉換成其中一個空的輸出緩衝區。 最後,您會要求 (或接收) 填滿的輸出緩衝區、取用其內容,並將它放回編解碼器。
<h3 id=qualityFloor“qualityFloor>”>Video Encoding< 的最小品質樓層/h3>
android.os.Build.VERSION_CODES#S
從 開始,Android 的 Video MediaCodecs 會強制執行最低品質樓層。 目的是要消除品質不佳的視訊編碼。 當編解碼器處於可變比特率 (VBR) 模式時,就會套用此品質樓層;當編解碼器處於常數比特率 (CBR) 模式時,不會套用它。 品質樓層強制執行也受限於特定大小範圍;此大小範圍目前適用於大於 320x240 到 1920x1080 的視訊解析度。
當此品質樓層生效時,編解碼器和支援的架構程序代碼將可運作,以確保產生的影片至少為「公平」或「良好」品質。 用來選擇這些目標的計量是 VMAF (Video Multi-method Assessment Function) ,所選測試序列的目標分數為 70。
一般效果是某些影片會產生比原本設定更高的比特率。 對於以非常低比特率設定的影片而言,這最值得注意;編解碼器會使用比特率,決定更可能產生「公平」或「良好」品質影片。 另一種情況是影片包含非常複雜的內容, (許多動作和詳細數據) ;在這類設定中,編解碼器會視需要使用額外的比特率,以避免遺失所有內容的詳細數據。
此品質樓層不會影響以高比特率擷取的內容, (高比特率應該已經為編解碼器提供足夠的容量來編碼所有詳細數據) 。 品質樓層不會在 CBR 編碼上運作。 品質樓層目前不適用於 320x240 或更低解析度的解析度,也不會在解析度高於 1920x1080 的影片上運作。
<h3>數據類型</h3>
編解碼器會處理三種數據:壓縮的數據、原始音訊數據和原始視訊數據。 這三種數據都可以使用 ByteBuffer ByteBuffers
來處理,但您應該使用 Surface
進行原始視訊數據的 ,以改善編解碼器效能。 Surface 會使用原生視訊緩衝區,而不需將其對應或複製到 ByteBuffers;因此,更有效率。 使用 Surface 時,您通常無法存取原始視訊數據,但您可以使用 ImageReader
類別來存取未經保護的譯碼 (原始) 視訊畫面。 這可能比使用 ByteBuffers 更有效率,因為某些原生緩衝區可能會對應到 ByteBuffer#isDirect 直接 ByteBuffers。 使用 ByteBuffer 模式時,您可以使用 類別和 #getInputImage getInput
/#getOutputImage OutputImage(int)
來存取原始視訊畫面。Image
<h4>壓縮緩衝區</h4>
編碼器的輸入緩衝區 () 和輸出緩衝區 (,) 根據 MediaFormat#KEY_MIME格式的類型包含壓縮的數據。 對於視訊類型,這通常是單一壓縮的視訊畫面。 對於音訊數據,這通常是單一存取單位, (編碼的音訊區段通常包含數毫秒的音訊,因為格式類型) 所指定,但此需求稍微寬鬆,因為緩衝區可能包含多個編碼的音訊存取單位。 不論是哪一種情況,緩衝區都不會在任意位元組界限上啟動或結束,而是在框架/存取單位界限上,除非它們以標幟 #BUFFER_FLAG_PARTIAL_FRAME
。
<h4>原始音頻緩衝區</h4>
原始音訊緩衝區包含整個PCM音訊數據框架,這是每個通道順序的一個範例。 每個 PCM 音訊範例都是以原生位元組順序的 16 位帶正負號整數或浮點數。 只有在 MediaFormat 的 MediaFormat#KEY_PCM_ENCODING在 MediaCodec #configure configure(…)
期間設定為 AudioFormat#ENCODING_PCM_FLOAT,並針對譯碼器或#getInputFormat
編碼器確認#getOutputFormat
時,才能使用 float PCM 編碼的原始音頻緩衝區。 在 MediaFormat 中檢查 float PCM 的範例方法如下:
static boolean isPcmFloat(MediaFormat format) {
return format.getInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT)
== AudioFormat.ENCODING_PCM_FLOAT;
}
為了擷取簡短數位中,緩衝區的一個通道包含16位帶正負號的整數音訊數據,可以使用下列程式代碼:
// Assumes the buffer PCM encoding is 16 bit.
short[] getSamplesForChannel(MediaCodec codec, int bufferId, int channelIx) {
ByteBuffer outputBuffer = codec.getOutputBuffer(bufferId);
MediaFormat format = codec.getOutputFormat(bufferId);
ShortBuffer samples = outputBuffer.order(ByteOrder.nativeOrder()).asShortBuffer();
int numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
if (channelIx < 0 || channelIx >= numChannels) {
return null;
}
short[] res = new short[samples.remaining() / numChannels];
for (int i = 0; i < res.length; ++i) {
res[i] = samples.get(i * numChannels + channelIx);
}
return res;
}
<h4>原始視訊緩衝區</h4>
在 ByteBuffer 模式視訊緩衝區中,會根據其 MediaFormat#KEY_COLOR_FORMAT色彩格式來配置。 您可以從 取得支援的色彩格式作為數位。#getCodecInfo
CodecCapabilities#colorFormats colorFormats
.
MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType(…)
.
視訊編解碼器可能支援三種色彩格式:<ul><li><強>式原生原始視訊格式:</strong> 這是所標示CodecCapabilities#COLOR_FormatSurface
,而且可以與輸入或輸出 Surface 搭配使用。</li li><<>強>式彈性 YUV 緩衝區</強>式 (,例如 CodecCapabilities#COLOR_FormatYUV420Flexible
) :這些可以搭配輸入/輸出 Surface 以及 ByteBuffer 模式使用。<#getInputImage getInput
/#getOutputImage OutputImage(int)
/li li>><<strong>other, specific formats:</strong> 這些通常只在 ByteBuffer 模式中受到支援。 某些色彩格式是廠商特定的。 其他則是在中 CodecCapabilities
定義。 對於相當於彈性格式的色彩格式,您仍然可以使用 #getInputImage getInput
/#getOutputImage OutputImage(int)
。</li></ul>
自 起 android.os.Build.VERSION_CODES#LOLLIPOP_MR1
,所有視訊編解碼器都支持彈性的 YUV 4:2:0 緩衝區。
<h4>在舊版裝置<上存取原始視訊位元節緩衝區/h4>
android.os.Build.VERSION_CODES#LOLLIPOP
在和 Image
支援之前,您必須使用 MediaFormat#KEY_STRIDE
和 MediaFormat#KEY_SLICE_HEIGHT
輸出格式值來瞭解原始輸出緩衝區的配置。 <p class=注意> :在某些裝置上,配量高度會公告為 0。 這可能表示配量高度與框架高度相同,或配量高度是對齊某些值的框架高度, (通常是2個) 的冪。 可惜的是,在此案例中,沒有標準且簡單的方法可告訴實際配量高度。 此外,平面格式的 U
垂直步幅也未指定或定義,但通常是配量高度的一半。
MediaFormat#KEY_WIDTH
和 MediaFormat#KEY_HEIGHT
鍵會指定視訊畫面的大小;不過,對於大部分的視訊 (圖片) 只會佔用視訊畫面的一部分。 這以「裁剪矩形」表示。
您必須使用下列索引鍵,從 #getOutputFormat 輸出格式取得原始輸出影像的裁剪矩形。 如果這些索引鍵不存在,影片會佔用整個視訊畫面。裁剪矩形會在套用任何 MediaFormat#KEY_ROTATION旋轉之前,>在輸出框架 <em>的內容中<瞭解。 <表格樣式=“width: 0%”><thead tr<>th>Format Key</>><th th Type/<>>th th< Description><</th/tr<>/thead<>><tbody><tr<>td<>MediaFormat#KEY_CROP_LEFT
/<>>td<><> 左座標 (x) 裁剪矩形</td></tr><><td<>MediaFormat#KEY_CROP_TOP
/td 整數><></Td><td>裁剪矩形/td/td>MediaFormat#KEY_CROP_RIGHT
><<<> td></<<>><>>td td 的頂端座標 (y) x) 強式減號 x) <強式減號 1</>強>式裁剪矩形<</td<>/>><<><MediaFormat#KEY_CROP_BOTTOM
td td 整數></><>td<>td 底 (坐標 (y) <強式減號 1</強>式減號>的裁剪矩形</td/tr>><<td>< colspan=3> 右座標和底部座標可以視為裁剪輸出影像最右有效數據行/最下層有效數據列的座標。 </td></tr></tbody></table>
旋轉) 之前,視訊畫面的大小 (可以計算如下:
MediaFormat format = decoder.getOutputFormat(…);
int width = format.getInteger(MediaFormat.KEY_WIDTH);
if (format.containsKey(MediaFormat.KEY_CROP_LEFT)
&& format.containsKey(MediaFormat.KEY_CROP_RIGHT)) {
width = format.getInteger(MediaFormat.KEY_CROP_RIGHT) + 1
- format.getInteger(MediaFormat.KEY_CROP_LEFT);
}
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
if (format.containsKey(MediaFormat.KEY_CROP_TOP)
&& format.containsKey(MediaFormat.KEY_CROP_BOTTOM)) {
height = format.getInteger(MediaFormat.KEY_CROP_BOTTOM) + 1
- format.getInteger(MediaFormat.KEY_CROP_TOP);
}
<p class=note 另請注意> ,在 BufferInfo#offset BufferInfo.offset
裝置上的意義不一致。 在某些裝置上,位移指向裁剪矩形的左上方圖元,而在大部分的裝置上,則指向整個框架的左上方圖元。
<h3>狀態</h3>
在其生命週期中,編解碼器在概念上存在於三種狀態的其中一種:已停止、執行或釋放。 已停止的統一狀態實際上是三種狀態的合併:未初始化、已設定和錯誤,而執行狀態則概念上會進行三個子狀態:Flushed、Running 和 End-of-Stream。
<center><img src=“../../../images/media/mediacodec_states.svg“ style=”width: 519px;height: 356px“ alt=”MediaCodec 狀態圖“></center>
當您使用其中一個 Factory 方法建立編解碼器時,編解碼器會處於未初始化的狀態。 首先,您必須透過 #configure configure(…)
進行設定,這會將它帶入 [已設定] 狀態,然後呼叫 #start
將其移至 [執行中] 狀態。 在此狀態下,您可以透過上述的緩衝區佇列操作來處理數據。
執行狀態有三個子狀態:Flushed、Running 和 End-of-Stream。 緊接在編解碼器處於 Flushed 子狀態之後 #start
,它會保存所有緩衝區。 一旦取消佇列第一個輸入緩衝區,編解碼器就會移至 [執行中] 子狀態,在其中花費大部分的時間。 當您使用 #BUFFER_FLAG_END_OF_STREAM數據流結尾標記將輸入緩衝區排入佇列時,編解碼器會轉換成 Stream 結束子狀態。 在此狀態下,編解碼器不再接受進一步的輸入緩衝區,但仍會產生輸出緩衝區,直到輸出到達數據流結束為止。 針對譯碼器,您可以使用 隨時回到 Flushed 子狀態 #flush
。 <p class=note><strong>Note:</strong> Backed state only supported state for decoders, and may not work for encoders, (行為未定義) 。
呼叫 #stop
以將編解碼器傳回未初始化的狀態,其中可能會再次設定編解碼器。 當您使用編解碼器完成時,您必須呼叫 #release
來釋放它。
在少數情況下,編解碼器可能會遇到錯誤,並移至 Error 狀態。 這會使用來自佇列作業的無效傳回值進行通訊,或有時透過例外狀況進行通訊。 再次呼叫 #reset
來讓編解碼器可供使用。 您可以從任何狀態呼叫它,將編解碼器移回未初始化的狀態。 否則,呼叫 #release
以移至終端機 [已發行] 狀態。
<h3>建立</h3>
使用 MediaCodecList
建立特定 MediaFormat
的 MediaCodec。 譯碼檔案或數據流時,您可以從 取得所需的格式 MediaExtractor#getTrackFormat MediaExtractor.getTrackFormat
。 插入您想要使用 MediaFormat#setFeatureEnabled MediaFormat.setFeatureEnabled
新增的任何特定功能,然後呼叫 MediaCodecList#findDecoderForFormat MediaCodecList.findDecoderForFormat
以取得可處理該特定媒體格式的編解碼器名稱。 最後,使用 #createByCodecName
建立編解碼器。 <p class=note><strong Note:</strong>> On android.os.Build.VERSION_CODES#LOLLIPOP
,格式EncoderForFormat
MediaCodecList.findDecoder
/不能包含 MediaFormat#KEY_FRAME_RATE幀速率。 使用 format.setString(MediaFormat.KEY_FRAME_RATE, null)
來清除格式中的任何現有幀速率設定。
您也可以使用 建立特定 MIME 類型的慣用 #createDecoderByType createDecoder
/#createEncoderByType EncoderByType(String)
編解碼器。 不過,這無法用來插入功能,而且可能會建立無法處理特定所需媒體格式的編解碼器。
<h4>建立安全譯碼器</h4>
在版本和更早版本 android.os.Build.VERSION_CODES#KITKAT_WATCH
上,安全編解碼器可能不會列在 MediaCodecList
中,但可能仍可在系統上使用。 只有名稱可以具現化存在的安全編解碼器,只要附加 ".secure"
至一般編解碼器的名稱, (所有安全編解碼器的名稱都必須以 ".secure"
.) #createByCodecName
結尾,如果系統上沒有編解碼器,則會擲回 IOException
。
從 android.os.Build.VERSION_CODES#LOLLIPOP
開始,您應該使用 CodecCapabilities#FEATURE_SecurePlayback
媒體格式的功能來建立安全譯碼器。
<h3>初始化</h3>
建立編解碼器之後,如果您想要以異步方式處理數據,可以使用 來設定回呼 #setCallback setCallback
。 然後,#configure 使用特定媒體格式設定編解碼器。 這是當您可以指定影片製作者的輸出 Surface
–產生原始視訊數據的編解碼器 (例如影片譯碼器) 。 您也可以設定安全編解碼器的解密參數, (請參閱 MediaCrypto
) 。 最後,由於某些編解碼器可以在多個模式中運作,因此您必須指定它是否要當做譯碼器或編碼器運作。
由於 android.os.Build.VERSION_CODES#LOLLIPOP
,您可以查詢已設定狀態的結果輸入和輸出格式。 您可以在啟動編解碼器之前,先使用此方法來驗證產生的組態,例如色彩格式。
如果您想要使用影片取用者原生處理原始輸入視訊緩衝區,–處理原始視訊輸入的編解碼器,例如視訊編碼器 –使用 #createInputSurface
設定之後,為您的輸入數據建立目的地 Surface。 或者,呼叫 來設定編解碼器,以使用先前建立 #createPersistentInputSurface 持續性輸入介面 #setInputSurface
。
<h4 id=CSD“CSD>”>Codec-specific Data</h4>
某些格式,特別是 AAC 音訊和 MPEG4、H.264 和 H.265 視訊格式,需要以包含設定數據或編解碼器特定數據的緩衝區作為前置詞的實際數據。 處理這類壓縮格式時,此數據必須在任何框架數據之後 #start
和之前提交至編解碼器。 這類數據必須使用呼叫#queueInputBuffer queueInputBuffer
中的旗標#BUFFER_FLAG_CODEC_CONFIG
來標記。
Codec 特定數據也可以包含在 ByteBuffer 專案中傳遞至#configure configure
具有索引鍵 「csd-0」、“csd-1」 等的格式。這些索引鍵一律包含在從 取得的MediaExtractor#getTrackFormat MediaExtractor
追蹤MediaFormat
中。 格式的編解碼器特定數據會在 時 #start
自動提交至編解碼器;您 <強>式「不得<」/「強> 式」明確提交此數據。 如果格式不包含編解碼器特定數據,您可以根據格式需求,選擇使用指定數目的緩衝區來提交它。 如果是 H.264 AVC,您也可以串連所有編解碼器特定的數據,並將其提交為單一編解碼器組態緩衝區。
Android 會使用下列編解碼器特定的數據緩衝區。 這些也需要以追蹤格式設定,才能正確 MediaMuxer
進行追蹤設定。 每個參數集和標示為 (<sup>*</sup>) 的編解碼器特定數據區段都必須以 的起始程式代碼 "\x00\x00\x00\x01"
開頭。
<樣式>td。NA { background: #ccc; } .mid > tr > td { vertical-align: middle; }</style><table><thead><>th><>Format</th CSD buffer #0</th th>TH CSD buffer #1</th<>th>CSD buffer #2</th><></thead<>tbody class=mid<>td>><AAC</td td><td>Decoder specific information from ESDS<sup*</sup>></td<>class=NA>Not Used/td td td><class=NA>Not Used<</Td></tr td><>><VORBIS</td td td>標識符標頭/td<>td>安裝程式標頭<</td><><td 類別=NA>Not Used</td></tr<>td<>>OPUS</td td><td>Id header</td><>td Td Pre-skip in nanosecs<br> (unsigned 64 位 ByteOrder#nativeOrder native-order integer.) br><這會覆寫標識符標頭中的預先略過值。</td td td><>Seek Pre-roll in nanosecs<br> (unsigned 64 位 ByteOrder#nativeOrder native-order integer.) </td></tr><><td>FLAC/td><td>“fLaC<”, ASCII 中的 FLAC 數據流標記,<br> 後面接著 STREAMINFO 區塊 (強制元數據區塊) ,br<> 選擇性地接著任意數目的其他元數據區塊</td td><類別=NA>未使用/<td><td 類別=NA>Not Used</td></tr><tr><td>MPEG-4</td>><decoder-specific information from ESDS<sup>*</sup></td><td class=NA>Not Used</td><class=NA>Not Used</td></tr>><<>td H.264 AVC</td><td>SPS (Sequence Parameter Sets<sup>*</sup>) </td td><>PPS (Picture Parameter Sets sup>*</sup>) </td><td td class=NA>Not Used</td/tr<>><>td<> H.265 HEVC</td<>td>VPS (Video Parameter Sets<<sup>*</sup>) +<br> SPS (Sequence Parameter Sets<sup>*</sup>) +br><PPS (Picture Parameter Sets<sup>*</sup>) </td td><class=NA>Not Used</td><class=NA>Not Used</td/tr><<>>td>< VP9/td><>VP9 <CodecPrivate Data (optional) </td><class=NA>Not Used/td<>td class=NA>Not Used<</td<>/tr><tr td>AV1/td< AV1 AV1 AV1CodecConfigurationRecord Data (選擇性) </td<>td 類別=NA Not Used</td td><td class=NA>>Not Used</td></tr<>/tbody<>/table<>>><>
<p class=note><strong>Note:</strong> care 必須小心,如果編解碼器在啟動后立即或不久後排清,再傳回任何輸出緩衝區或輸出格式變更,因為編解碼器特定數據可能會在排清期間遺失。 您必須在這類排清之後,使用標示 #BUFFER_FLAG_CODEC_CONFIG
為的緩衝區重新提交數據,以確保適當的編解碼器作業。
編碼器 (或產生壓縮數據的編解碼器,) 會在以 #BUFFER_FLAG_CODEC_CONFIG 編解碼器-config 旗標標示的輸出緩衝區中,建立並傳回編解碼器特定數據。 包含編解碼器特定數據的緩衝區沒有有意義的時間戳。
<h3>數據處理</h3>
每個編解碼器都會維護 API 呼叫中緩衝區識別碼所參考的一組輸入和輸出緩衝區。 成功呼叫 #start
客戶端之後,不會「擁有」輸入或輸出緩衝區。 在同步模式中,呼叫 #dequeueInputBuffer dequeueInput
/#dequeueOutputBuffer OutputBuffer(…)
以取得 (從編解碼器取得輸入或輸出緩衝區) 擁有權。 在異步模式中,您將透過回呼自動接收可用的緩衝區 Callback#onInputBufferAvailable MediaCodec.Callback.onInput
/Callback#onOutputBufferAvailable OutputBufferAvailable(…)
。
取得輸入緩衝區時,請填入數據,並使用 &ndash 將其提交至編解碼器 #queueInputBuffer queueInputBuffer
;如果使用 #queueSecureInputBuffer queueSecureInputBuffer
解密,則為 。 請勿提交具有相同時間戳的多個輸入緩衝區 (,除非它是標示為這類) 的編解碼器特定數據。
編解碼器接著會透過 Callback#onOutputBufferAvailable onOutputBufferAvailable
異步模式的回呼傳回只讀輸出緩衝區,或以同步模式回應 #dequeueOutputBuffer dequeueOutputBuffer
呼叫。 處理輸出緩衝區之後,請呼叫其中 #releaseOutputBuffer releaseOutputBuffer
一個方法,將緩衝區傳回編解碼器。
雖然您不需要立即將/釋放緩衝區重新提交至編解碼器,但保留輸入和/或輸出緩衝區可能會停止編解碼器,而且此行為與裝置相關。 <具體>來說,編解碼器可能會在產生輸出緩衝區時予以保留,直到 <em>all</em> 未處理的緩衝區已釋放/重新提交為止。</strong> 因此,請嘗試盡可能保留到可用的緩衝區。
視 API 版本而定,您可以透過三種方式處理數據:<使用<<>>>><<<>>緩衝區陣列/td td 支援</td 的緩衝區陣列</td td Td 的 api 版本 <= 20<br Jelly Bean/KitKat</>><th API 版本 >= 21<br>>Lollipop 和 later</th<>/tr></thead><tbody><tr><td>><>同步 API><td>Deprecated</td/tr<><>td<>> 同步 API using buffers</td<>td class=NA>Not< Available/>><td Supported</td></tr<>tr<>td>異步 API using buffers</td<>td td class=NA>Not Available</td<>>Supported</td></tr></tbody></table>
<h4>使用緩衝區</h4 進行異步處理>
由於 android.os.Build.VERSION_CODES#LOLLIPOP
,慣用的方法是在呼叫 #configure configure
之前設定回呼,以異步方式處理數據。 異步模式會稍微變更狀態轉換,因為您必須在 之後#flush
呼叫 #start
,才能將編解碼器轉換為執行中的子狀態,並開始接收輸入緩衝區。 同樣地,在對編解碼器進行初始呼叫 start
時,會直接移至 [執行中] 子狀態,並開始透過回呼傳遞可用的輸入緩衝區。
<center><img src=“../../../images/media/mediacodec_async_states.svg“ style=”width: 516px;height: 353px“ alt=”MediaCodec state diagram for asynchronous operation“></center>
MediaCodec 通常會在異步模式中像這樣使用:
MediaCodec codec = MediaCodec.createByCodecName(name);
MediaFormat mOutputFormat; // member variable
codec.setCallback(new MediaCodec.Callback() {
{@literal @Override}
void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {
ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
// fill inputBuffer with valid data
…
codec.queueInputBuffer(inputBufferId, …);
}
{@literal @Override}
void onOutputBufferAvailable(MediaCodec mc, int outputBufferId, …) {
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
// bufferFormat is equivalent to mOutputFormat
// outputBuffer is ready to be processed or rendered.
…
codec.releaseOutputBuffer(outputBufferId, …);
}
{@literal @Override}
void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {
// Subsequent data will conform to new format.
// Can ignore if using getOutputFormat(outputBufferId)
mOutputFormat = format; // option B
}
{@literal @Override}
void onError(…) {
…
}
{@literal @Override}
void onCryptoError(…) {
…
}
});
codec.configure(format, …);
mOutputFormat = codec.getOutputFormat(); // option B
codec.start();
// wait for processing to complete
codec.stop();
codec.release();
<h4>使用 Buffers</h4 進行同步處理>
由於,android.os.Build.VERSION_CODES#LOLLIPOP
您應該使用 和/或#getInputImage getInput
#getOutputImage OutputImage(int)
/即使在同步模式中使用編解碼器時,擷#getInputBuffer getInput
/#getOutputBuffer OutputBuffer(int)
取輸入和輸出緩衝區。 這可讓架構進行特定優化,例如處理動態內容時。 如果您呼叫 #getInputBuffers getInput
/#getOutputBuffers OutputBuffers()
,就會停用此優化。
<p class=note><strong>Note:</strong> 不會同時混合使用緩衝區和緩衝區陣列的方法。 具體來說,只有在將輸出緩衝區標識符清除佇列后或之後,才直接呼叫 getInput
/OutputBuffers
,其值為 #INFO_OUTPUT_FORMAT_CHANGED
。#start
MediaCodec 通常會在同步模式中像這樣使用:
MediaCodec codec = MediaCodec.createByCodecName(name);
codec.configure(format, …);
MediaFormat outputFormat = codec.getOutputFormat(); // option B
codec.start();
for (;;) {
int inputBufferId = codec.dequeueInputBuffer(timeoutUs);
if (inputBufferId >= 0) {
ByteBuffer inputBuffer = codec.getInputBuffer(…);
// fill inputBuffer with valid data
…
codec.queueInputBuffer(inputBufferId, …);
}
int outputBufferId = codec.dequeueOutputBuffer(…);
if (outputBufferId >= 0) {
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
// bufferFormat is identical to outputFormat
// outputBuffer is ready to be processed or rendered.
…
codec.releaseOutputBuffer(outputBufferId, …);
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// Subsequent data will conform to new format.
// Can ignore if using getOutputFormat(outputBufferId)
outputFormat = codec.getOutputFormat(); // option B
}
}
codec.stop();
codec.release();
<h4>使用緩衝區陣列進行同步處理 (已被取代) </h4>
在版本 android.os.Build.VERSION_CODES#KITKAT_WATCH
和之前版本中,輸入和輸出緩衝區集是由 ByteBuffer[]
數位表示。 成功呼叫 #start
之後,請使用 #getInputBuffers getInput
/#getOutputBuffers OutputBuffers()
擷取緩衝區陣列。 當非負數) 時,請使用緩衝區標識碼作為這些陣列的索引 (,如下列範例所示。 請注意,陣列大小與系統所使用的輸入和輸出緩衝區數目之間沒有固有的相互關聯,雖然陣列大小會提供上限。
MediaCodec codec = MediaCodec.createByCodecName(name);
codec.configure(format, …);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
for (;;) {
int inputBufferId = codec.dequeueInputBuffer(…);
if (inputBufferId >= 0) {
// fill inputBuffers[inputBufferId] with valid data
…
codec.queueInputBuffer(inputBufferId, …);
}
int outputBufferId = codec.dequeueOutputBuffer(…);
if (outputBufferId >= 0) {
// outputBuffers[outputBufferId] is ready to be processed or rendered.
…
codec.releaseOutputBuffer(outputBufferId, …);
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
outputBuffers = codec.getOutputBuffers();
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// Subsequent data will conform to new format.
MediaFormat format = codec.getOutputFormat();
}
}
codec.stop();
codec.release();
<h4>數據流結束處理</h4>
當您到達輸入數據的結尾時,您必須在呼叫 #queueInputBuffer queueInputBuffer
中指定 #BUFFER_FLAG_END_OF_STREAM
旗標,向編解碼器發出訊號。 您可以在最後一個有效的輸入緩衝區上執行此動作,或提交具有數據流結尾旗標集的其他空白輸入緩衝區。 如果使用空白緩衝區,則會忽略時間戳。
編解碼器會繼續傳回輸出緩衝區,直到最終會藉由在 集合#dequeueOutputBuffer dequeueOutputBuffer
中BufferInfo
指定相同數據流結尾旗標,或透過 Callback#onOutputBufferAvailable onOutputBufferAvailable
傳回來發出輸出數據流結尾的訊號。 這可以在最後一個有效的輸出緩衝區上,或在最後一個有效輸出緩衝區之後的空白緩衝區上設定。 應該忽略這類空白緩衝區的時間戳。
除非已排清編解碼器,或已停止並重新啟動,否則在發出輸入數據流結尾的訊號之後,請勿提交其他輸入緩衝區。
<h4>使用輸出 Surface</h4>
使用輸出 Surface
時,數據處理幾乎與 ByteBuffer 模式相同;不過,將無法存取輸出緩衝區,並以值表示 null
。 例如 #getOutputBuffer getOutputBuffer
/#getOutputImage Image(int)
,會傳回 null
,而且 #getOutputBuffers
會傳回只 null
包含 -s 的陣列。
使用輸出 Surface 時,您可以選取是否要在介面上呈現每個輸出緩衝區。 您有三個選項:<ul><li><strong>請勿轉譯 buffer:</strong> Call #releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, false)
。</li>li strong>轉譯具有默認時間戳的緩衝區:</strong> 呼叫 #releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, true)
。<><</li>li strong>轉譯具有特定時間戳的緩衝區:</strong> 呼叫 #releaseOutputBuffer(int, long) releaseOutputBuffer(bufferId, timestamp)
。<><</li></ul>
因為 android.os.Build.VERSION_CODES#M
,默認時間戳是緩衝區的 BufferInfo#presentationTimeUs 簡報時間戳, (轉換成 nanoseconds) 。 它並未在該之前定義。
android.os.Build.VERSION_CODES#M
此外,您也可以使用 #setOutputSurface setOutputSurface
動態變更輸出 Surface。
將輸出轉譯至 Surface 時,Surface 可能會設定為卸除 Surface 不會及時耗用的過多畫面 (格) 。 或者,它可以設定為不要卸除過多的畫面格。 在後者模式中,如果 Surface 未快速取用輸出畫面格,最終會封鎖譯碼器。 android.os.Build.VERSION_CODES#Q
在未定義確切的行為之前,除了檢視介面 (SurfaceView 或 TextureView) 一律捨棄過多畫面格例外。 因為 android.os.Build.VERSION_CODES#Q
預設行為是卸除過多的畫面格。 應用程式可以將目標設為 SDKandroid.os.Build.VERSION_CODES#Q
,並以其設定格式將金鑰MediaFormat#KEY_ALLOW_FRAME_DROP
0
設定為 ,以退出宣告非檢視表面 (,例如 ImageReader 或 SurfaceTexture) 。
<轉譯至 Surface</h4 時的 h4>轉換>
如果編解碼器設定為 Surface 模式,則任何裁剪矩形、MediaFormat#KEY_ROTATION旋轉和 #setVideoScalingMode 視訊縮放模式都會自動套用其中一個例外狀況: <p class=note> 在發行之前 android.os.Build.VERSION_CODES#M
,軟體譯碼器可能無法在轉譯至 Surface 時套用旋轉。 可惜的是,沒有可識別軟體譯碼器的標準和簡單方式,或者它們是否套用旋轉,而不是藉由試用。
另外還有一些注意事項。 <p class=note 請注意> ,在 Surface 上顯示輸出時,不會考慮像素外觀比例。 這表示如果您使用 #VIDEO_SCALING_MODE_SCALE_TO_FIT
模式,您必須放置輸出 Surface,使其具有適當的最終顯示外觀比例。 相反地,您只能針對圖元比例為平方圖元的內容使用 #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
模式, (像素外觀比例或 1:1) 。 <p class=note> 另請注意,從發行起 android.os.Build.VERSION_CODES#N
, #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
模式可能無法正確運作,視訊旋轉 90 或 270 度。 <p class=note> 設定視訊縮放模式時,請注意,每次輸出緩衝區變更后都必須重設。 #INFO_OUTPUT_BUFFERS_CHANGED
由於事件已被取代,因此您可以在每次輸出格式變更之後執行此動作。
<h4>使用輸入 Surface</h4>
使用輸入 Surface 時,沒有可存取的輸入緩衝區,因為緩衝區會自動從輸入介面傳遞至編解碼器。 呼叫 #dequeueInputBuffer dequeueInputBuffer
會擲IllegalStateException
回 ,並#getInputBuffers
傳回強式 MUST NOT</strong> 寫入的假ByteBuffer[]
數組<>。
呼叫 #signalEndOfInputStream
以發出數據流結尾的訊號。 輸入介面將會在此呼叫之後立即停止將數據提交至編解碼器。
<h3>搜尋 &自適性播放支援</h3>
視訊譯碼器 (,以及取用壓縮視訊數據的一般編解碼器,) 對於搜尋和格式變更的行為不同,不論它們是否支援和設定為調適型播放。 您可以透過 檢查譯碼器是否支援 CodecCapabilities#FEATURE_AdaptivePlayback調適型播放 CodecCapabilities#isFeatureSupported CodecCapabilities.isFeatureSupported(String)
。 只有在您將編解碼器設定為譯碼至 Surface
時,才會啟用視訊譯碼器的自適性播放支援。
<h4 id=KeyFrames>“KeyFrames”>Stream Boundary and Key Frames</h4>
在適當的數據流界限之後 #start
或 #flush
開始輸入數據很重要:第一個畫面必須是主要畫面格。 <>em 主要畫面格</em> 可以自行譯碼 (,這表示 I 畫面格) ,而且主要畫面格之後不會顯示任何畫面格參考主要畫面格之前的畫面。
下表摘要說明各種視訊格式的適當主要畫面格。 <table>thead><>tr><th Format</th>><Key frame/th></tr></thead<>tbody class=mid<>tr<>td>VP9/VP8</td td td>><a suitable intraframe, where no subsequent frames< refer to frames prior to this frame.<<br> (這類主要畫面格沒有特定名稱。) </td/tr tr><><td><> H.265 HEVC/td td<>Td>版的 WID 或 CRA</td></tr><tr<>td>H.264 AVC<</td td><>Td Td<<>><>>< MPEG-4<br H.263<br>>MPEG-2</td><>適用於沒有後續畫面參照框架的 I-frame在這個框架之前。<br> (這類主要畫面格沒有特定名稱。) </td<>/tr<>/tbody></table>
<h4>若為不支援調適型播放的譯碼器, (包括未譯碼到 Surface) </h4>
為了開始譯碼與先前提交數據不相鄰的數據 (亦即在搜尋) 您 <強式>MUST</strong> 排清譯碼器之後。 由於所有輸出緩衝區都會在排清時立即撤銷,因此您可能想要先發出訊號,然後在呼叫 flush
之前等候數據流結束。 排清之後的輸入數據必須從適當的數據流界限/主要畫面格開始。 <p class=note>strong Note:</strong> the format of the data submitted after a flush must not change; #flush
does not support format discontinuities; for that, a full #stop
- #start
#configure configure(…)
- cycle is musty.><
<p class=note strong>另請注意<<>:/strong> 如果您在 &ndash 之後#start
太快排清編解碼器;一般而言,在收到第一個輸出緩衝區或輸出格式變更之前,–您必須將編解碼器特定數據重新提交至編解碼器。 如需詳細資訊,請參閱 codec-specific-data 一節。
<h4>針對支援 和 的譯碼器,設定為調適型播放</h4>
為了開始譯碼與先前送出的數據不相鄰的數據 (,也就是在搜尋) <>之後,就不需要</em> 來排清譯碼器;不過,在不連續之後的輸入數據必須從適當的數據流界限/主要畫面格開始。
對於某些視訊格式,也就是 H.264、H.265、VP8 和 VP9 ,也可以變更圖片大小或設定中串流。 若要這樣做,您必須將整個新的編解碼器特定組態數據與主要畫面格一起封裝成單一緩衝區, (包括任何開始程式碼) ,並將其提交為 <強>式一般</強式> 輸入緩衝區。
在進行圖片大小變更之前,以及傳回任何具有新大小的畫面之前,您會收到#INFO_OUTPUT_FORMAT_CHANGED
來自 或 Callback#onOutputBufferAvailable onOutputFormatChanged
回呼的傳回值#dequeueOutputBuffer dequeueOutputBuffer
。 <p class=note><strong>Note:</strong> ,就像編解碼器特定數據的案例一樣,在變更圖片大小之後不久呼叫時 #flush
請小心。 如果您尚未收到圖片大小變更的確認,您必須重複要求新的圖片大小。
<h3>錯誤處理</h3>
處理站方法 #createByCodecName createByCodecName
,並在 #createDecoderByType createDecoder
/#createEncoderByType EncoderByType
失敗時擲回 IOException
,您必須攔截或宣告以通過。 從不允許它的編解碼器狀態呼叫 方法時,MediaCodec 方法會擲 IllegalStateException
回;這通常是因為不正確的應用程式 API 使用狀況。 涉及安全緩衝區的方法可能會擲回 CryptoException
,其具有可從 CryptoException#getErrorCode
取得的進一步錯誤資訊。
內部編解碼器錯誤會導致 CodecException
,這可能是因為媒體內容損毀、硬體失敗、資源耗盡等等,即使應用程式使用 API 正確也一致。 接收 CodecException
時的建議動作可藉由呼叫 CodecException#isRecoverable
和 CodecException#isTransient
來判斷:<ul><li><強>式可復原錯誤:</strong> If isRecoverable()
傳回 true,則呼叫 #stop
、 #configure configure(…)
和 #start
以復原。</li><li><強>性暫時性錯誤:</strong> 如果isTransient()
傳回 true,則資源暫時無法使用,而且稍後可能會重試方法。</li>li強式嚴重錯誤:</strong> 如果 同時isRecoverable()
傳isTransient()
回 false,則 CodecException
為嚴重,而且必須 #reset 重設或 #release 釋放編解碼器。<>><</li></ul>
isRecoverable()
和 isTransient()
不會同時傳回 true。
<h2 id=History“History>”>Valid API Calls and API History</h2>
本節摘要說明每個狀態的有效 API 呼叫,以及 MediaCodec 類別的 API 歷程記錄。 如需 API 版本號碼,請參閱 android.os.Build.VERSION_CODES
。
<style> .api tr th, .api >> tr >> td { text-align: center; padding: 4px 4px; } .api > tr th { vertical-align: bottom; } .api > tr >> td { vertical-align: middle; } .sml > tr > th, .sml > tr > td { text-align: center; padding: 2px 4px; } .fn { text-align: left; } .fn > code > a { font: 14px/19pxBoto Condensed, sans-serif; } .deg45 { white-space: nowrap; background: none; border: none; vertical-align: bottom; width: 30px; height:83px;} .deg45 > div { transform: skew (-45deg, 0deg) translate (1px, -67px) ; transform-origin: bottom 0; width: 30px; height: 20px; } .deg45 > div div > { border: 1px solid #ddd; background: #999; height: 90px; width: 42px; } .deg45 > div div > div > { transform: skew (45deg, 0deg) translate (-55px, 55px) rotate (-45deg) ; }</風格>
<table align=“right” style=“width: 0%”>thead<>tr>><th Symbol/th th>><Meaning<</th></tr></thead<>tbody class=sml><tr><td>●</td><>td supported</td></><><tr td>⁕</td>><Semantics changed</td></tr><tr><td>○</td><>td Td 實驗支援</td/tr tr><><td><<>[ ]</td td>><Deprecated</td/tr><td>><><⎋</td><td>Restricted to surface input mode</td/td></tr><>>< td⎆</td td>><Restricted to surface output mode/td/<><><>td><▧/td>><Restricted to ByteBuffer input mode<</td/td></tr><><td>↩</td td><>Restricted to synchronous mode/<td></tr><><td>⇄</td td>><限制為異步模式</td/tr><<>td><> ( ) </td><td>可以呼叫,但不應</td></tr></tbody></table>
<表格樣式=“width: 100%;”><thead class=api><tr><th class=deg45><div><div style=“background:#4285f4”>><div Uninitialized</div></div></div></th><class=deg45><div div><style=“background:#f4b400”>><div Configured</div></><><div/th><th class=deg45><><div style=“background:#e67c73”><div>Flushed</div></div/div><></th th><class=deg45><div><div style=“background:#0f9d58”>><div Running</div></><div/div></th><class=deg45><div><div style=“background:#f7cb4d”>><div End of Stream</div><><></div/th><class=deg45><><div style=“background:#db4437”><>div Error</><div/div><></th class><=deg45><div div style=“background:#666”div><><>發行</div/div><></><div/th><></th><th colspan=“8”>SDK Version</th></tr th><><colspan=“7”>State</><>th th Method</><>th th 16</><>th 17/th 18<><></<>>th 19</th 20</>><th th>21</th><><>22</th><>23</th<>/tr></thead<>tbody class=api<>tr<>td></td><><><><<><>><<><><><>></td td/td><td class=fn<>#createByCodecName createByCodecName
/td>><●</td<>> td●</td><td>●</td><td>●</td><td>●</><<>td td●/><><td td●/>><<td td●/td></tr><><td></td td<><><><><><<><<>><><>><<>>/td td td/td td/td td 類別=fn>#createDecoderByType createDecoderByType
</td td>●</td><td <>●/td><td <>●/><<>td td●/><><td td●/td td●/<><>td><>< td●/<><>><td td●/td/><tr td><></><td td></><><<><>><td td><></Td><td></td td/td>><< td><類別=fn<#createEncoderByType createEncoderByType
>/td td><>●/td><> td●<</><><td td●/<><>td td●/td<<>> td●/td<><> td●/><>td●</td><td><●/><td/tr><td><></td><td></td><td></td td><<><><>/td td/><<<>>><td td/<>td td 類別=fn>#createPersistentInputSurface createPersistentInputSurface
</<>><td td/><><><>><<<>><><><><td>><<><> td●</td></tr tr><><td>16+</td td-/td><<>td><>-</td><td>-</td><td><-/><><td td-/<><>td><類別=fn<>#configure configure
/td td●/td<><>>><< td●/td td●/td<<>> td●</td><>><td>●</td><td>⁕</td><td>●</td><td>●</td<>/tr<>>>< td-</td>><td 18+</td><> td-</td><>< td-/<<>>td td-/td td-/td><><>><<<> 類別=fn>#createInputSurface createInputSurface
</Td><td></td td<>/td><<>><⎋/td>>< td⎋</td><<> td⎋/<>><td td⎋/><<>td td⎋/td>>><<<td⎋/td/tr<><>td-td>-<</td>>><<> 16+</>><td td 16+</td td><> (16+) </td<>td>-</td<<><>> 類別=fn<>#dequeueInputBuffer dequeueInputBuffer
/>><<td td●/<<>>td td●/td td▧/<<>>td><><><<> td▧/td td▧/td<>>⁕▧↩</><<>td td▧↩/td td▧↩/>td><><</Tr><tr>td>-<</td td<>td> 16+</td>><><td>16+</<>>td td 16+/>><<td td 16+</>><<td td-/td<>td class=fn<>#dequeueOutputBuffer dequeueOutputBuffer
/td td <><>●/td><<> td●/td>>< td●</td><td●</td>><<td>●</td td><>⁕↩</td<>td>↩</td<>td>↩</td<>/tr<<>>td>-</td<>td<>-/td>><td 16+/td><>td 16+</td><>td 16+<</td<>td>-</td<>td td>-</td td><class=fn>/td><td>●</td td>●</td><<><> td●/><<<><>>td td●/td td●/td><<> td●/td><> td●</td<><>td●/<>td/tr><tr<>td>18+</td<>td>18+</td td>><18+#flush flush
<</Td><td>18+/td td<>>18+</td td>18+<</td<>><td><-/<>td td class=fn#getCodecInfo getCodecInfo
<>/<<>>><><td td/td<<>> td●/td td●/<><><>>td●</td<><> td●/><<>td td●/td td●/td><><></tr><<>td-</td td>-/td><td>>><< (21+) </td><td>21+</><>td td (21+) </><td td td>-</td><>< td><td 類別=fn>#getInputBuffer getInputBuffer
</td<>><>><< td/td td/<><>td td/><><td><td></td td><>●</td><td>●</td<>td>●</td></tr><td>>><-<><</><>td 16+/td td<>> (16+<) </td<>> (16+) </<>>td td td-</td><td><td><class=fn><#getInputBuffers getInputBuffers
/td td<>●</td<>td>>●</td><> td●</<<>>td td●/<>><td td●/td<>td>[⁕↩]</td td><>[↩]/td<>> td[↩]<</td></tr><tr><td>-</td td 21+</td><>><td> (21+) </td><td> (21+) </td><td> (21+) </td><td td>>><<-</td><td 類別=fn<>#getInputFormat getInputFormat
/td><td></td<>td></><td td></><<><>td td/><><td td><●/td td><td>●/<td td●/td></tr><td>><-</td>><<>>< (21+) </td><td>21+</td td><> (21+) </td><> td td>-<</td<<>>類別=fn>#getInputImage getInputImage
</<>td td td><<<>><>></Td><td></td><td></td><>><><○</td<>td>●/<>td td>●<</td<>/tr><><>td 18+/td td 18+/td<>>td 18+<</td<><> td 18+</td>><td 18+/td td 18+</td<>td>><>18+</td td<>td>-</td td><類別=fn<#getName getName
>/td<>td></><><td><<> td●/><><td td●/td<>> td●</td<>>< td●/><><td td●/td><>●</td></tr><Tr><td>-<<><>/td td<>td> (21+) </td<>>td 21+</><>td td 21+</td><> td td-</td><>< td-/td><td 類別=fn>#getOutputBuffer getOutputBuffer
</td>>><<<>< td td/><><td td/><><>td<td></td td><>●</td<>td>●</td<>td>●</td<>/tr><tr<>td>>-<<></td>><16+/td td 16+/td>><td 16+</td><>16+<</td<<>>> td td-<></Td><td class=fn><#getOutputBuffers getOutputBuffers
/td><td>●</td td>●</td <><><> td●/>><<td td●/td>>< td●</td><> td[⁕↩]</td><> td[↩]</td td<>>[↩]</td/tr<><>td<>>-/<td><td>21+/td td>16+<</td<>td 16+</td<><>>>td 16+</<>>td td td-</><td td><-/td<>td class=fn>#getOutputFormat()
</td td><><●/td><<> td●/td><<> td●/td><> td●</Td><td>●</td td<>>●</td><td>●</><td td <>●/td<>/tr<><>td>-</td<>td><><> td (21+) </<>>td td 21+</td td 21+</td<>>td-</td><>><td>-</td><td 類別=fn<>#getOutputFormat(int)
/td td<><>/td>><</<><><><><>><><>td/td td●</td><<> td●/td>><< td●/td></tr<>tr><td>-</td td-><></Td><td> (21+) </td><td>21+</td>><td 21+</><td td><-/><td td td>-</td><td 類別=fn#getOutputImage getOutputImage
<>/td><>< td/td td>>><><><<<<>><<>><></td td td/td td○/><td td td><●/td td>><●</td<>/tr><<>td>-</td><td td>-<</>>><<td td> 16+</td td>>< (16+) </td>>< td td-</td><>< 類別=fn>#queueInputBuffer queueInputBuffer
</td><><td>●</td<>td>●</td><td>●</td>>< td●</<<>>td td●/>><<td td⁕/td<><>td●/td>><<td●/td></tr><><td>-</td><><><td>-</td td>><16+</td><td> (16+) </<>td td><>-</>><<td 類別=fn<>#queueSecureInputBuffer queueSecureInputBuffer
/td●</td<>>>><< td●/td><>< td●/td td●/>><td●><><</Td><td>⁕</td td><>●</td><td>●</td<>/tr<>td<>>16+><></td td 16+/td>><td 16+/td<>>td 16<+<</td><>< td 16+/td td 16<+/td><>td>16+</td><td><類別=fn><#release release
/td td><>●</td<>td>●</td<>td>●</><<><><>td td●/td td●/td><td><●/td>><< td●/td <>><td●/td></tr><tr><td>-</td><td>-</td td><>-</td><td>16+/td td 16+<</<>td><>td>-</><td><>< 類別=fn>#releaseOutputBuffer(int, boolean)
</td><>●</td><>< td●/td<><> td●/td td●</td><>><td>●</td><td>⁕</td<>td>●/td><td>⁕<</td></tr>><<> td-</td<>td<>-/><td td td>-</td td 21+/td<>>td 21+/td><>td 21+<</td<>td td><><td>-</td><td 類別=fn>#releaseOutputBuffer(int, long)
</td td<><>/td><><<<>>><></td td/>><<<><>td/td td/td td⎆/td><td><⎆/td><> td⎆</td></tr><><td>21+</td td><>21+</td><td>21+</td><td>21+</td><>td 21+</>><td td 21+</><td td><-/td><td 類別=fn#reset reset
<>/><><td td/td><<<<>>>><><>< td/td td td/td td●><><></Td><td>●</td td><>●</td<>/tr tr<>><td>21+</td><td>-</<>td td>-</<>td td>-</td<>> td-</td td-/td><>><>< td td-</td<>td class=fn#setCallback(Callback) setCallback
<>/td td td><></Td><td></td><td></td><td><<>></><>td td●</td td●</<<<>>#setCallback(Callback, Handler) ⁕
>>td td/td<>/tr<>><> td-</td>><23+</td td-/td><<> td td>-</td<>><td-></Td><td>-</td td><>-</td><td 類別=fn<#setInputSurface setInputSurface
>/td><>< td/td<>td><<><>/td td/><<<>><>td td/td td/><><><<>td><> td⎋</td></tr><tr><td>23+</td><td>23+</td<>>23+</td td>23+</td>><><td 23+</><>td td (23+) </td><td> (23+) </td><類別=fn#setOnFrameRenderedListener setOnFrameRenderedListener
<>/td<<><><>> td/td td/<><><>><td td/><><td><td></td td><></td>><<○ ⎆/td<>/tr tr<><>td>-</td<>>td 23+</>><td td 23+/td><>td 23+/td td 23+</td><>23+<<<<>>/td td td-</td><td>>< 類別=fn>#setOutputSurface setOutputSurface
</td><td/td>< td><></td>><< td<>><><></td td/><<>><<<>>>td td⎆</td></tr<>tr<>td>19+/td td 19+<</td>><td 19+/td><>td>><19+<</Td><td>19+</td><td> (19+) </td><td>-</><td td class=fn>#setParameters setParameters
</><>><<>>><<<<<>>td td●/><><td td●/td <>><td●/td<>td●/td<>> td><td<●/td/tr<>><td<>-</td td>>>< (16+) </td><td> (16+) </td><td>16+/td td<>> (16+<) </td<>> (16+) </<>td>< 類別=fn><#setVideoScalingMode setVideoScalingMode
/td td><td><><⎆/td td>><⎆</td td><⎆/td>><<>< td⎆/><><<>><td td⎆/td td⎆/td<>td <>⎆/td><>< td⎆/td<>/tr><>>< td (29+) </td><td>29+</td><td>29+</td td><>29+</td td>>< (29+) /td<>td> (<29+) </><td td td>-</td td class=fn#setAudioPresentation setAudioPresentation
></<>><td<>td/t><><><><><><><><><><><td></td><td></td></tr><><td>-</td><><>>< 18+</><>td td 18+</<>td td td>-</<>td td td>-</td td-</td<>> td 類別=fn<#signalEndOfInputStream signalEndOfInputStream
>/td<<>>td/td><><td></td td><>⎋</td><td>⎋</td><> td⎋/><><td td⎋</>><<td td⎋/td><td <>⎋/<>td/tr<><>td>-</td><>td 16+</td<>>td 21+ (⇄) </tdtd>-</td td>><-</td td><>-</td><>><< class=fn#start start
></><td td <>●/><><td td●/td>><<td●/td <>><td●/td <>><td●/td>>< td⁕><</Td><td>●</td td<>>●</td<>/tr tr<><>td>-</td><td<>-/><>td td 16+</><>td td 16+/td><>td 16+<</td td<<>>-/<>td td td>-</td<>td class=fn#stop stop
<>/td td><><●/td td><>●</td<>td>●</td><td>●<></td td><●/<>><td td●/td>><<td●/td<><> td●/td<>/tr<>/tbody></table>
的 android.media.MediaCodec
Java 檔。
此頁面的部分是根據 所建立和共用的工作進行修改,並根據 2.5 屬性授權中所述的詞彙來使用。
欄位
BufferFlagCodecConfig |
已淘汰.
這表示標示為的緩衝區包含編解碼器初始化/編解碼器特定數據,而不是媒體數據。 |
BufferFlagDecodeOnly |
已淘汰.
這表示緩衝區已譯碼並更新譯碼器的內部狀態,但不會產生任何輸出緩衝區。 |
BufferFlagEndOfStream |
已淘汰.
這會發出數據流結尾的訊號 i。 |
BufferFlagKeyFrame |
已淘汰.
這表示標示為 (編碼) 緩衝區包含主要畫面格的數據。 |
BufferFlagPartialFrame |
已淘汰.
這表示緩衝區只包含框架的一部分,而且譯碼器應該批處理數據,直到沒有這個旗標的緩衝區出現在譯碼框架之前。 |
BufferFlagSyncFrame |
已淘汰.
這表示標示為 (編碼) 緩衝區包含主要畫面格的數據。 |
ConfigureFlagEncode |
已淘汰.
如果要將此編解碼器當做編碼器使用,請傳遞此旗標。 |
ConfigureFlagUseBlockModel |
已淘汰.
如果要搭配 |
ConfigureFlagUseCryptoAsync |
已淘汰.
此旗標應該只用於安全譯碼器。 |
CryptoModeAesCbc |
已淘汰.
MediaCodec 類別可用來存取低階媒體編解碼器 i。 |
CryptoModeAesCtr | |
CryptoModeUnencrypted | |
InfoOutputBuffersChanged |
已淘汰.
輸出緩衝區已變更,客戶端必須參考從這個點傳 |
InfoOutputFormatChanged |
已淘汰.
輸出格式已變更,後續的數據會遵循新的格式。 |
InfoTryAgainLater |
已淘汰.
如果在呼叫 |
ParameterKeyHdr10PlusInfo |
在下一個佇列輸入畫面上設定 HDR10+ 元數據。 |
ParameterKeyLowLatency |
啟用/停用低延遲譯碼模式。 |
ParameterKeyOffsetTime |
指定要在時間戳之後新增的微秒) 中的位移 (。 |
ParameterKeyRequestSyncFrame |
要求編碼器「即將」產生同步畫面。 |
ParameterKeySuspend |
暫時暫停/繼續輸入數據的編碼。 |
ParameterKeySuspendTime |
出現時 |
ParameterKeyTunnelPeek |
當編解碼器設定為通道模式時,控制第一個畫面格的視訊查看,其中會暫停 |
ParameterKeyVideoBitrate |
實時變更視訊編碼器的目標比特率。 |
VideoScalingModeScaleToFit |
已淘汰.
內容會縮放至表面尺寸 |
VideoScalingModeScaleToFitWithCropping |
已淘汰.
內容會縮放、維持其外觀比例、使用整個介面區,可能會裁剪內容。 |
屬性
CanonicalName |
擷取基礎編解碼器名稱。 |
Class |
傳回這個 |
CodecInfo |
取得編解碼器資訊。 |
Handle |
基礎Android實例的句柄。 (繼承來源 Object) |
InputFormat |
成功傳回之後 |
JniIdentityHashCode |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
JniPeerMembers |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 |
Metrics |
傳回目前編解碼器實例的相關計量數據。 |
Name |
擷取編解碼器名稱。 |
OutputFormat |
在 dequeueOutputBuffer 傳回 |
PeerReference |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
SupportedVendorParameters |
傳回廠商參數名稱的清單。 |
ThresholdClass |
此 API 支援適用於 Android 的 Mono 基礎結構,並不適合直接從您的程式代碼使用。 (繼承來源 Object) |
ThresholdType |
此 API 支援適用於 Android 的 Mono 基礎結構,並不適合直接從您的程式代碼使用。 (繼承來源 Object) |
方法
Clone() |
建立並傳回這個 對象的複本。 (繼承來源 Object) |
Configure(MediaFormat, Surface, MediaCodecConfigFlags, MediaDescrambler) |
設定要與 descrambler 搭配使用的元件。 |
Configure(MediaFormat, Surface, MediaCrypto, MediaCodecConfigFlags) |
設定元件。 |
CreateByCodecName(String) |
如果您知道您想要具現化的元件確切名稱,請使用這個方法來具現化它。 |
CreateDecoderByType(String) |
具現化支援指定mime類型的輸入數據的慣用譯碼器。 |
CreateEncoderByType(String) |
具現化慣用的編碼器,以支援指定mime類型的輸出數據。 |
CreateInputSurface() |
要求 Surface 用來作為編碼器的輸入,以取代輸入緩衝區。 |
CreatePersistentInputSurface() |
建立可搭配通常具有輸入介面的編解碼器使用的永續性輸入介面,例如視訊編碼器。 |
DequeueInputBuffer(Int64) |
傳回輸入緩衝區的索引,如果目前沒有可用的緩衝區,則傳回要填入有效數據或 -1 的索引。 |
DequeueOutputBuffer(MediaCodec+BufferInfo, Int64) |
清除輸出緩衝區的佇列,最多會封鎖 「timeoutUs」 微秒。 |
Dispose() |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
Dispose(Boolean) |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
Equals(Object) |
指出其他物件是否「等於」這個物件。 (繼承來源 Object) |
Flush() |
清除元件的輸入和輸出埠。 |
GetHashCode() |
傳回此物件的雜湊碼值。 (繼承來源 Object) |
GetInputBuffer(Int32) |
|
GetInputBuffers() |
已淘汰.
擷取一組輸入緩衝區。 |
GetInputImage(Int32) |
傳回已清除佇列輸入緩衝區索引的可寫入 Image 物件,以包含原始輸入視訊畫面。 |
GetOutputBuffer(Int32) |
傳回已清除佇列輸出緩衝區索引的唯讀 ByteBuffer。 |
GetOutputBuffers() |
已淘汰.
擷取輸出緩衝區集。 |
GetOutputFormat(Int32) |
傳回特定輸出緩衝區的輸出格式。 |
GetOutputFrame(Int32) |
傳回 |
GetOutputImage(Int32) |
會傳回包含原始視訊畫面之已清除佇列輸出緩衝區索引的唯讀 Image 物件。 |
GetParameterDescriptor(String) |
描述具有名稱的參數。 |
GetQueueRequest(Int32) |
|
JavaFinalize() |
當垃圾收集判斷物件不再參考物件時,垃圾收集行程會在物件上呼叫。 (繼承來源 Object) |
MapHardwareBuffer(HardwareBuffer) |
將 |
Notify() |
喚醒正在等候此物件監視器的單一線程。 (繼承來源 Object) |
NotifyAll() |
喚醒正在等候此物件監視器的所有線程。 (繼承來源 Object) |
QueueInputBuffer(Int32, Int32, Int32, Int64, MediaCodecBufferFlags) |
填入指定索引處的輸入緩衝區範圍之後,請將它提交至元件。 |
QueueSecureInputBuffer(Int32, Int32, MediaCodec+CryptoInfo, Int64, MediaCodecBufferFlags) |
|
Release() |
釋放編解碼器實例所使用的資源。 |
ReleaseOutputBuffer(Int32, Boolean) |
如果您使用緩衝區完成,請使用這個呼叫將緩衝區傳回編解碼器,或在輸出介面上轉譯它。 |
ReleaseOutputBuffer(Int32, Int64) |
如果您使用緩衝區完成,請使用此呼叫來更新其表面時間戳,並將它傳回編解碼器,以在輸出介面上呈現它。 |
Reset() |
將編解碼器傳回至其初始 (未初始化) 狀態。 |
SetAudioPresentation(AudioPresentation) |
設定音訊簡報。 |
SetCallback(MediaCodec+Callback) |
設定默認迴圈器上可採取動作之 MediaCodec 事件的異步回呼。 |
SetCallback(MediaCodec+Callback, Handler) |
設定默認迴圈器上可採取動作之 MediaCodec 事件的異步回呼。 |
SetHandle(IntPtr, JniHandleOwnership) |
設定 Handle 屬性。 (繼承來源 Object) |
SetInputSurface(Surface) |
設定編解碼器 (e. |
SetOnFirstTunnelFrameReadyListener(Handler, MediaCodec+IOnFirstTunnelFrameReadyListener) |
註冊在譯碼第一個輸出畫面格時要叫用的回呼,並準備好在設定為通道模式的 |
SetOnFrameRenderedListener(MediaCodec+IOnFrameRenderedListener, Handler) |
註冊在輸出介面上轉譯輸出框架時要叫用的回呼。 |
SetOutputSurface(Surface) |
動態設定編解碼器的輸出介面。 |
SetParameters(Bundle) |
將其他參數變更傳達至元件實例。 |
SetVideoScalingMode(VideoScalingMode) |
如果在先前呼叫中指定表面,以 |
SignalEndOfInputStream() |
在輸入時發出串流結束訊號。 |
Start() |
成功設定元件之後,請呼叫 |
Stop() |
完成譯碼/編碼會話,請注意編解碼器實例會保持作用中,並準備好 |
SubscribeToVendorParameters(IList<String>) |
訂閱廠商參數,讓這些參數會出現在 中 |
ToArray<T>() |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
ToString() |
傳回物件的字串表示。 (繼承來源 Object) |
UnregisterFromRuntime() |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
UnsubscribeFromVendorParameters(IList<String>) |
取消訂閱廠商參數,讓這些參數不會出現在 中 |
Wait() |
讓目前的線程等到喚醒為止,通常是em <notified/em>或<em>interrupted</em>。>< (繼承來源 Object) |
Wait(Int64) |
讓目前的線程等到喚醒為止,通常是em <notified/em>或<em>interrupted</em>,或直到經過一定數量的實時為止。<> (繼承來源 Object) |
Wait(Int64, Int32) |
讓目前的線程等到喚醒為止,通常是em <notified/em>或<em>interrupted</em>,或直到經過一定數量的實時為止。<> (繼承來源 Object) |
明確介面實作
IJavaPeerable.Disposed() |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
IJavaPeerable.DisposeUnlessReferenced() |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
IJavaPeerable.Finalized() |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
IJavaPeerable.JniManagedPeerState |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
IJavaPeerable.SetJniIdentityHashCode(Int32) |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates) |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
IJavaPeerable.SetPeerReference(JniObjectReference) |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 (繼承來源 Object) |
擴充方法
JavaCast<TResult>(IJavaObject) |
執行 Android 執行時間檢查的類型轉換。 |
JavaCast<TResult>(IJavaObject) |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 |
GetJniTypeName(IJavaPeerable) |
MediaCodec 類別可用來存取低階媒體編解碼器 i。 |