前言
MediaCodec前面已經(jīng)做了簡(jiǎn)介卸留,那么這一篇就是使用了父晶。
參考文章
Creation 創(chuàng)建
1陡舅、createByCodecName(String)
使用MediaCodecList
為特定的MediaFormat
創(chuàng)建MediaCodec
。
- 解碼文件或流時(shí)仪糖,可以從
MediaExtractor#getTrackFormat
獲得所需的格式挂脑。 - 使用
MediaFormat#setFeatureEnabled
注入要添加的所有特定功能,然后調(diào)用MediaCodecList#findDecoderForFormat
以獲取可以處理該特定媒體格式的編解碼器的名稱(chēng)景醇。 - 最后臀稚,使用
createByCodecName(String)
創(chuàng)建編解碼器。
2三痰、createDecoder/EncoderByType(String)
根據(jù)指定的MIME type來(lái)創(chuàng)建codec吧寺。
注意:使用這種方法創(chuàng)建的codec不能用于注入特征,并且可能創(chuàng)建無(wú)法處理特定所需媒體格式的編解碼器酒觅。
擴(kuò)展:
/**
* Sets whether a feature is to be enabled ({@code true}) or disabled
* ({@code false}).
*
* If {@code enabled} is {@code true}, the feature is requested to be present.
* Otherwise, the feature is requested to be not present.
*
* @param feature the name of a {@link MediaCodecInfo.CodecCapabilities} feature.
*
* @see MediaCodecList#findDecoderForFormat
* @see MediaCodecList#findEncoderForFormat
* @see MediaCodecInfo.CodecCapabilities#isFormatSupported
*/
public void setFeatureEnabled(@NonNull String feature, boolean enabled) {
setInteger(KEY_FEATURE_ + feature, enabled ? 1 : 0);
}
public void setFeatureEnabled (String feature, boolean enabled)
設(shè)置是啟用(true)還是禁用(false)功能撮执。 如果enabled為true微峰,則要求該功能存在舷丹。 否則,要求該功能不存在蜓肆。
兩個(gè)方案如下::
private void createDecoderCodec() throws IOException {
MediaExtractor mExtractor = new MediaExtractor();
//extract /sdcard/test.mp4
mExtractor.setDataSource("/sdcard/test.mp4");
int trackCount = mExtractor.getTrackCount();
for (int i = 0; i < trackCount; i++) {
//1. 解碼文件或流時(shí)颜凯,可以從MediaExtractor#getTrackFormat獲得所需的格式。
MediaFormat format = mExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
//方案一
//2. 使用MediaFormat#setFeatureEnabled注入要添加的所有特定功能,創(chuàng)建安全的解碼器仗扬。
format.setFeatureEnabled(MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback,true);
//3. 然后調(diào)用MediaCodecList#findDecoderForFormat以獲取可以處理該特定媒體格式的編解碼器的名稱(chēng)症概。
MediaCodecList list = new MediaCodecList(REGULAR_CODECS);
String encoderForFormat = list.findDecoderForFormat(format);
//4. 使用createByCodecName(String)創(chuàng)建編解碼器。
MediaCodec codec = MediaCodec.createByCodecName(encoderForFormat);
//方案二
MediaCodec decoderByType = MediaCodec.createDecoderByType(mime);
}
}
}
3早芭、創(chuàng)建安全的解碼器
在Android 4.4(KITKAT_WATCH)及之前版本彼城,安全的編解碼器沒(méi)有被列在MediaCodecList中,但是仍然可以在系統(tǒng)中使用。
安全編解碼器只能夠通過(guò)名字進(jìn)行實(shí)例化募壕,其名字是在常規(guī)編解碼器的名字后附加.secure標(biāo)識(shí)(所有安全編解碼器的名字都必須以.secure結(jié)尾)调炬,調(diào)用createByCodecName(String)方法創(chuàng)建安全編解碼器時(shí),如果系統(tǒng)中不存在指定名字的編解碼器就會(huì)拋出IOException異常舱馅。
從Android 5.0(LOLLIPOP)及之后版本缰泡,您應(yīng)該使用媒體格式的CodecCapabilities#FEATURE_SecurePlayback
功能來(lái)創(chuàng)建安全的解碼器。
Initialization 初始化
根據(jù)之前我們提到的流程代嗤,創(chuàng)建完編解碼器之后棘钞,需要進(jìn)行configure
。如果只是需要原始視頻數(shù)據(jù)干毅,直接configure
就可以了宜猜。如果需要結(jié)合Surface使用,需要增加configure
的surface
參數(shù)硝逢。
如果要使用視頻使用者(用于處理原始視頻輸入的編解碼器宝恶,例如視頻編碼器)本地處理原始輸入視頻緩沖區(qū),請(qǐng)?jiān)谂渲煤笫褂?code>createInputSurface()為輸入數(shù)據(jù)創(chuàng)建目標(biāo)Surface
趴捅。 或者垫毙,通過(guò)調(diào)用setInputSurface(Surface)
將編解碼器設(shè)置為使用以前創(chuàng)建的持久輸入表面。
Codec-specific Data 編解碼器專(zhuān)用數(shù)據(jù)
某些格式拱绑,尤其是AAC音頻和MPEG4综芥,H.264和H.265視頻格式,要求實(shí)際數(shù)據(jù)的前綴是許多包含設(shè)置數(shù)據(jù)或編解碼器特定數(shù)據(jù)的緩沖區(qū)猎拨。
處理此類(lèi)壓縮格式時(shí)膀藐,必須在start()
之后和任何幀數(shù)據(jù)之前將這些數(shù)據(jù)提交給編解碼器。 必須在對(duì)queueInputBuffer
的調(diào)用中使用標(biāo)志BUFFER_FLAG_CODEC_CONFIG
標(biāo)記此類(lèi)數(shù)據(jù)红省。
特定格式的編解碼器數(shù)據(jù)也可以包含在傳遞的格式中额各,以使用鍵“ csd-0”,“ csd-1”等在ByteBuffer條目中進(jìn)行配置吧恃。這些鍵始終包含在從MediaExtractor#getTrackFormat
獲得的MediaFormat
軌道中虾啦。
特定格式的編解碼器數(shù)據(jù)在start()
時(shí)自動(dòng)提交給編解碼器, 您不得明確提交此數(shù)據(jù)。
如果該格式不包含編解碼器專(zhuān)用數(shù)據(jù)痕寓,則可以根據(jù)格式要求選擇使用正確數(shù)量的指定緩沖區(qū)使用指定數(shù)量提交傲醉。 對(duì)于H.264 AVC,您還可以連接所有特定于編解碼器的數(shù)據(jù)呻率,并將其作為單個(gè)編解碼器配置緩沖區(qū)提交硬毕。
Android使用以下特定于編解碼器的數(shù)據(jù)緩沖區(qū)。 為了正確配置MediaMuxer
軌道礼仗,還需要將其設(shè)置為軌道格式吐咳。 每個(gè)參數(shù)集和標(biāo)有(*)的編解碼器專(zhuān)用數(shù)據(jù)部分必須以“ \ x00 \ x00 \ x00 \ x01”
的起始代碼開(kāi)頭逻悠。
AAC audio, MPEG4, H.264韭脊, H.265 video格式的數(shù)據(jù)作為輸入源解碼的時(shí)候蹂风,需要指定一個(gè)特殊的前綴設(shè)置信息,這個(gè)信息通常包含在數(shù)據(jù)中乾蓬,但是需要自己提取出來(lái)惠啄,在mediacodec執(zhí)行start之后提交這些數(shù)據(jù),比如h264的sps和pps任内,在queueinputbuffer的時(shí)候flag設(shè)置為BUFFER_FLAG_CODEC_CONFIG提交給解碼器撵渡。同樣這些數(shù)據(jù)可以在configure的時(shí)候提交給mediacodec,效果和前邊的一樣:
mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(sps));//sps是一個(gè)包含sps信息的byte數(shù)組
mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(pps));//pps是一個(gè)包含pps信息的byte數(shù)組
當(dāng)調(diào)用start方法啟動(dòng)時(shí)這些信息同樣會(huì)傳給mediacodec死嗦。你絕不能直接提交這些數(shù)據(jù)趋距。 如果格式不包含編解碼器特定數(shù)據(jù),則可以根據(jù)格式要求越除,選擇使用指定數(shù)量的緩沖區(qū)以正確的順序提交它节腐。 在H.264 AVC的情況下,還可以連接所有編解碼器專(zhuān)用數(shù)據(jù)并將其作為單個(gè)編解碼器配置緩沖區(qū)提交摘盆。
下圖所有帶*的值必須加上前綴"\x00\x00\x00\x01"
注意:如果在返回任何輸出緩沖區(qū)或輸出格式更改之前立即或在啟動(dòng)后不久刷新編解碼器翼雀,則必須小心,因?yàn)榫幗獯a器特定的數(shù)據(jù)可能會(huì)在刷新過(guò)程中丟失孩擂。 刷新之后狼渊,必須使用標(biāo)有BUFFER_FLAG_CODEC_CONFIG的緩沖區(qū)重新提交數(shù)據(jù),以確保正確的編解碼器操作类垦。
編碼器(或生成壓縮數(shù)據(jù)的編解碼器)將在標(biāo)有codec-config標(biāo)志的輸出緩沖區(qū)中的任何有效輸出緩沖區(qū)之前狈邑,創(chuàng)建并返回特定于編解碼器的數(shù)據(jù)。 包含編解碼器特定數(shù)據(jù)的緩沖區(qū)沒(méi)有有意義的時(shí)間戳蚤认。
Data Processing 數(shù)據(jù)處理
每個(gè)codec都有一片屬于自己的輸入/輸出緩沖區(qū)米苹,每個(gè)緩沖區(qū)都有bufferID來(lái)指向。在調(diào)用start方法后砰琢,用戶(hù)不能訪(fǎng)問(wèn)任何的input buffer
和output buffer
蘸嘶。
在同步模式下,調(diào)用dequeueInput / OutputBuffer(…)
從編解碼器獲嚷任觥(或擁有)輸入或輸出緩沖區(qū)亏较。
在異步模式下莺褒,您將通過(guò)Callback#onInputBufferAvailable / Callback#onOutputBufferAvailable
回調(diào)自動(dòng)接收可用緩沖區(qū)掩缓。
模式 | 輸入方法 | 輸出方法 |
---|---|---|
同步模式 | dequeueInputBuffer() | dequeueOutputBuffer() |
異步模式 | MediaCodec.Callback.OnInputBufferAvailabe() | MediaCodec.Callback.OnInputBufferAvailabe() |
當(dāng)獲得inputbuffer(輸入方法執(zhí)行后)后,所有權(quán)交給了用戶(hù)遵岩,這些緩沖區(qū)由用戶(hù)填滿(mǎn)數(shù)據(jù)后需要使用queueInputBuffer
(加密數(shù)據(jù)的話(huà)請(qǐng)使用queueSecureInputBuffer
)提交緩沖區(qū)你辣,提交后緩沖區(qū)后所有權(quán)交給了codec巡通。注意不要為多個(gè)幀提供相同的時(shí)間戳,除非是配置信息舍哄,也就是標(biāo)記為BUFFER_FLAG_CODEC_CONFIG
的幀可以隨意使用時(shí)間戳宴凉。
當(dāng)獲得outputbuffer(輸出方法執(zhí)行)后,用戶(hù)可訪(fǎng)問(wèn)一個(gè)只讀的緩沖區(qū)表悬,當(dāng)使用完畢后弥锄,請(qǐng)調(diào)用releaseOutputBuffer
方法來(lái)將緩沖區(qū)返回給codec。
我們可以不立即queueinputbuffer/releaseOutputBuffer
到編解碼器蟆沫,但用戶(hù)持有input/outputbuffer可能會(huì)使編解碼器停止工作籽暇,并且此行為取決于設(shè)備。 編解碼器有可能在產(chǎn)生輸出緩沖區(qū)之前暫停饭庞,直到所有未完成的緩沖區(qū)queueinputbuffer/releaseOutputBuffer
戒悠。 因此,用戶(hù)最好每次獲得緩沖區(qū)后執(zhí)行釋放操作舟山。
根據(jù)API版本绸狐,你可以用三種方式處理數(shù)據(jù):
Asynchronous Processing using Buffers 使用緩沖區(qū)的異步處理
從LOLLIPOP開(kāi)始,首選方法是在調(diào)用configure方法之前通過(guò)設(shè)置回調(diào)來(lái)異步處理數(shù)據(jù)累盗。 異步模式會(huì)稍微改變狀態(tài)轉(zhuǎn)換步驟寒矿,在running狀態(tài)時(shí)必須在調(diào)用flush()之后調(diào)用start()方法,將編解碼器轉(zhuǎn)換為Running子狀態(tài)并開(kāi)始接收輸入緩沖區(qū)若债。 同樣劫窒,在初始調(diào)用開(kāi)始時(shí),codec將直接移至Running子狀態(tài)拆座,并通過(guò)回調(diào)開(kāi)始傳遞可用的輸入緩沖區(qū)主巍。
官方解釋如下圖:
MediaCodec通常在異步模式下這樣使用:
MediaCodec codec = MediaCodec.createByCodecName(name);
MediaFormat mOutputFormat; // member variable
codec.setCallback(new MediaCodec.Callback() {
@Override
void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {
ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
// fill inputBuffer with valid data
…
codec.queueInputBuffer(inputBufferId, …);
}
@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, …);
}
@Override
void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {
// Subsequent data will conform to new format.
// Can ignore if using getOutputFormat(outputBufferId)
mOutputFormat = format; // option B
}
@Override
void onError(…) {
…
}
});
codec.configure(format, …);
mOutputFormat = codec.getOutputFormat(); // option B
codec.start();
// wait for processing to complete
codec.stop();
codec.release();
設(shè)置回調(diào)方法必須在mediacodec創(chuàng)建之后,并且在configure方法之前挪凑。
MediaCodec.Callback共有四個(gè)方法:
void onError(MediaCodec codec, MediaCodec.CodecException e)//發(fā)生錯(cuò)誤時(shí)回調(diào)此方法
void onInputBufferAvailable(MediaCodec codec, int index)//當(dāng)inputbuffer可用時(shí)回調(diào)此方法
void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info)
//當(dāng)output方法可用時(shí)回調(diào)此方法
void onOutputFormatChanged(MediaCodec codec, MediaFormat format)//當(dāng)輸出格式變化時(shí)回調(diào)此方法
看一下幾個(gè)重要的方法:
- ByteBuffer getInputBuffer (int index)
該方法會(huì)返回一個(gè)已清空孕索、可寫(xiě)入的input緩沖區(qū),通過(guò)調(diào)用ByteBuffer.put(data)方法將data中的數(shù)據(jù)放到緩沖區(qū)后,也可以進(jìn)行其他處理躏碳,然后調(diào)用void queueInputBuffer (int index, int offset, int size, long presentationTimeUs, int flags)
就可以將緩沖區(qū)返回給codec搞旭。index
是回調(diào)函數(shù)中返回的index,offset
是緩沖區(qū)提交數(shù)據(jù)的起始未知菇绵,可以不從0開(kāi)始肄渗,size是需要提交的長(zhǎng)度,presentationTimeUs
是時(shí)間戳咬最,這個(gè)時(shí)間戳最好是按幀率來(lái)計(jì)算(單位:ns)翎嫡,當(dāng)使用surface作為輸出時(shí),這個(gè)時(shí)間會(huì)作為視頻的時(shí)間戳來(lái)顯示永乌;flags一般三個(gè)值:BUFFER_FLAG_CODEC_CONFIG
:配置信息惑申,BUFFER_FLAG_END_OF_STREAM
:結(jié)束標(biāo)志具伍,BUFFER_FLAG_KEY_FRAME
:關(guān)鍵幀,不建議使用圈驼。
在執(zhí)行此方法后index指向的緩沖區(qū)將不可訪(fǎng)問(wèn)人芽,繼續(xù)使用將會(huì)拋出異常。
- ByteBuffer getOutputBuffer (int index)
用法同getinputbuffer一樣绩脆。
- void releaseOutputBuffer (int index,boolean render)
void releaseOutputBuffer (int index,long renderTimestampNs)
這兩個(gè)方法都會(huì)釋放index所指向的緩沖區(qū)萤厅。
假如使用了surface,第二個(gè)參數(shù)傳入傳入true將會(huì)把數(shù)據(jù)先輸出給surface靴迫,當(dāng)surface不再使用時(shí)立即返回給codec祈坠,傳入long型時(shí):
如果在SurfaceView上渲染緩沖區(qū),則可以使用時(shí)間戳在特定時(shí)間渲染緩沖區(qū)(在緩沖區(qū)時(shí)間戳之后或之后的VSYNC處)矢劲。為了達(dá)到這個(gè)目的赦拘,時(shí)間戳需要合理地接近當(dāng)前的nanoTime()。目前芬沉,這是在(1)秒內(nèi)設(shè)定的躺同。
一些注意事項(xiàng):
該緩沖區(qū)將不會(huì)返回到編解碼器,直到時(shí)間戳已經(jīng)過(guò)去并且該緩沖區(qū)不再被Surface使用丸逸。
緩沖區(qū)會(huì)按順序處理蹋艺,因此您可能會(huì)阻止后續(xù)緩沖區(qū)顯示在Surface上。如果您想對(duì)用戶(hù)操作做出反應(yīng)黄刚,這很重要捎谨。停止視頻或?qū)で蟆?br> 如果將多個(gè)緩沖區(qū)發(fā)送到要在同一個(gè)VSYNC上渲染的Surface,則會(huì)顯示最后一個(gè)緩沖區(qū)憔维,其他將被放棄涛救。
如果時(shí)間戳不與當(dāng)前系統(tǒng)時(shí)間“合理接近”,Surface將忽略時(shí)間戳业扒,并在最早的可行時(shí)間顯示緩沖區(qū)检吆。在這種模式下,它不會(huì)丟幀程储。
為獲得最佳性能和質(zhì)量蹭沛,當(dāng)您在所需渲染時(shí)間之前約兩個(gè)VSYNC的時(shí)間時(shí)調(diào)用此方法。對(duì)于60Hz的顯示器章鲤,這是大約33毫秒摊灭。
這段話(huà)的大概意思就是不要使用這個(gè)方法。
Synchronous Processing using Buffers 使用緩沖區(qū)的同步處理
從LOLLIPOP開(kāi)始败徊,即使在同步模式下使用編解碼器帚呼,也應(yīng)使用getInput / OutputBuffer(int)
和/或getInput / OutputImage(int)
檢索輸入和輸出緩沖區(qū)。 這允許框架進(jìn)行某些優(yōu)化集嵌,例如 處理動(dòng)態(tài)內(nèi)容時(shí)萝挤。 如果調(diào)用getInput / OutputBuffers()
御毅,則會(huì)禁用此優(yōu)化根欧。
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();
看一下重要方法:
int dequeueInputBuffer (long timeoutUs)
返回值是緩沖區(qū)的BufferId怜珍,假如返回值為-1則表示緩沖區(qū)不能使用。傳入的參數(shù)為正凤粗,則是最長(zhǎng)等待時(shí)間酥泛,為0則會(huì)立即返回緩沖區(qū)的id,負(fù)數(shù)則會(huì)無(wú)限等待嫌拣。
Synchronous Processing using Buffer Arrays (deprecated) 使用緩沖區(qū)數(shù)組的同步處理(不建議使用)
在Build.VERSION_CODES.KITKAT_WATCH
及更低版本中柔袁,輸入和輸出緩沖區(qū)的集合由ByteBuffer []
數(shù)組表示。 成功調(diào)用start()后异逐,使用getInput / OutputBuffers()
檢索緩沖區(qū)數(shù)組捶索。 使用緩沖區(qū)ID作為這些數(shù)組的索引(非負(fù)數(shù)時(shí)),如以下示例所示灰瞻。 請(qǐng)注意腥例,盡管數(shù)組大小提供了上限,但數(shù)組大小與系統(tǒng)使用的輸入和輸出緩沖區(qū)的數(shù)量之間沒(méi)有固有的相關(guān)性酝润。
MediaCodec通常在同步模式下這樣使用:
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();
End-of-stream
當(dāng)結(jié)束輸入數(shù)據(jù)時(shí)燎竖,發(fā)送如下代碼即可:
codec.queueInputBuffer(index,0,0,0,BUFFER_FLAG_END_OF_STREAM); //第三個(gè)時(shí)間戳可以隨意設(shè)置,空緩沖區(qū)的時(shí)間戳被忽略。
接受到這個(gè)信號(hào)后要销,codec將不再接受任何新的數(shù)據(jù)构回,在這個(gè)信號(hào)之前的數(shù)據(jù)會(huì)全部輸出。
除非已刷新疏咐,停止或重新啟動(dòng)編解碼器纤掸,否則請(qǐng)?jiān)诎l(fā)出輸入流結(jié)束信號(hào)后不要提交其他輸入緩沖區(qū)。
Using an Output Surface 使用surface作為輸出
使用surface做為輸出時(shí)與使用Bytebuffer基本一致浑塞,只是在surface模式下所有的bytebuffer和image全部為null茁肠。
releaseOutputBuffer(bufferId, false); //不會(huì)渲染到surface上
releaseOutputBuffer(bufferId, true); //使用默認(rèn)的時(shí)間戳渲染視頻
releaseOutputBuffer(bufferId, timestamp) //使用指定的時(shí)間戳渲染視頻
從Build.VERSION_CODES.M
開(kāi)始,默認(rèn)時(shí)間戳為緩沖區(qū)的BufferInfo#presentationTimeUs(轉(zhuǎn)換為納秒)
缩举。 在此之前未定義垦梆。
Using an Input Surface 使用surface作為輸入
使用surface作為輸入,沒(méi)有可訪(fǎng)問(wèn)的輸入緩沖區(qū)仅孩,因?yàn)榫彌_區(qū)會(huì)自動(dòng)從輸入表面?zhèn)鬟f到編解碼器托猩。調(diào)用 dequeueInputBuffer
會(huì)拋出IllegalStateException
,并且getInputBuffers()
返回一個(gè)不能寫(xiě)入的偽造ByteBuffer []數(shù)組辽慕。
調(diào)用signalEndOfInputStream()
以信號(hào)流結(jié)束京腥。 調(diào)用后,輸入Surface將立即停止向編解碼器提交數(shù)據(jù)溅蛉。