我試圖改善我們的應用程序的幀提取。基本上我所做的就是結合來自Grafika的MoviePlayer
的前向搜索解決方案和BigFlake的ExtractMpegFramesTest
來提取幀。對於提取,我尋找回前一個關鍵幀,然後正向解碼並僅保存最後一幀。像這樣的東西(見較完整的解釋我previous question):Android MediaCodec可以同時解碼到兩個曲面嗎?
decoder.releaseOutputBuffer(decoderStatus, doRender);
if (doRender) {
if (VERBOSE) Log.d(TAG, "awaiting decode of frame " + decodeCount);
outputSurface.awaitNewImage();
outputSurface.drawImage(false);
if(extractor.getSampleTime() == mPosition){
Log.d(TAG, "sampleTime: " + extractor.getSampleTime() + " mPosition: " + mPosition + "----- EXTRACTING FRAME");
long startWhen = System.currentTimeMillis();
outputSurface.saveFrame();
long frameSaveTime = System.currentTimeMillis() - startWhen;
Log.d(TAG, "sampleTime: frame saved in: " + frameSaveTime + " millisecond");
return;
}
decodeCount++;
}
的問題是有時尋求落後然後解碼向前時從extractor.getSampleTime()
檢索到的採樣時間似乎並不匹配,從直線前進的一個求。
我已經包含了日誌,使之更清楚:
position is the seeking position in microsecond
sampleTime: 12112100 -- position: 12139000 ----- FORWARD
sampleTime: 12120441 -- position: 12139000 ----- FORWARD
sampleTime: 12128783 -- position: 12139000 ----- FORWARD
sampleTime: 12137125 -- position: 12139000 ----- FORWARD
sampleTime: 12012000 -- position: 12139000 ----- BACKWARD
sampleTime: 12020341 -- position: 12139000 ----- BACKWARD
sampleTime: 12028683 -- position: 12139000 ----- BACKWARD
sampleTime: 12037025 -- position: 12139000 ----- BACKWARD
sampleTime: 12045366 -- position: 12139000 ----- BACKWARD
sampleTime: 12053708 -- position: 12139000 ----- BACKWARD
sampleTime: 12062050 -- position: 12139000 ----- BACKWARD
sampleTime: 12070391 -- position: 12139000 ----- BACKWARD
sampleTime: 12078733 -- position: 12139000 ----- BACKWARD
sampleTime: 12087075 -- position: 12139000 ----- BACKWARD
sampleTime: 12095416 -- position: 12139000 ----- BACKWARD
sampleTime: 12103758 -- position: 12139000 ----- BACKWARD
sampleTime: 12112100 -- position: 12139000 ----- BACKWARD
sampleTime: 12120441 -- position: 12139000 ----- BACKWARD
sampleTime: 12128783 -- position: 12139000 ----- BACKWARD
正如你所看到的,在向前尋找的。我不確定它爲什麼會發生,但這會導致表示幀和提取幀之間不匹配。此外,這種方法效率不高,因爲我必須設置一個extractor.getSampleTime()
可以達到定位12137125
同時尋求回來然後解碼前進,它只能達到12128783
EGLSurface
並在每次需要提取幀時對其解碼。根據前一個關鍵幀所需幀的距離,該操作可能需要3到5秒,對於多次提取而言肯定太長。
我想問一下,是否可以同時對兩個表面進行解碼器解碼(用於顯示的SurfaceView
和用於幀檢索的EGLSurface
),以便我可以潛在地解決這些準確性和性能問題。
我也嘗試過使用FFmpeg檢索幀之前,性能差不多。如果有更好的方法來檢索框架比使用OpenGL,我非常願意嘗試。
編輯:經過進一步測試,我可以匹配兩種方法中的extractor.getSampleTime()
,即使檢索到的幀有時可能與顯示幀不匹配。
編輯2:關於顯示的幀和提取的幀之間的不匹配,但實際上非常簡單,但它首先是相當混亂,如果你不知道怎麼MediaCodec
工作。我必須重讀每一位法登的評論以更好地理解這個問題(this就是那個給我那個「啊哈」的時刻)。
總之,解碼器喜歡消耗多個緩衝區之前,它吐出任何表示緩衝區。所以當前顯示的與當前的extractor.getSampleTime()
位置不一樣。所以,正確的值顯示,提取應該是輸出緩衝器的presentationTime,這樣的事情之間同步:
mCurrentSampleTime = mBufferInfo.presentationTimeUs;
瞭解此幫助解決許多多個神祕的問題(如爲什麼第一幀不在0的位置?)。希望這會幫助某人。