2016-08-19 60 views
1

我試圖改善我們的應用程序的幀提取。基本上我所做的就是結合來自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的位置?)。希望這會幫助某人。

回答

1

不是我的問題的具體答案,但我確實找到了一種方法來提高幀提取時間。基本上,如果你沒有任何嚴格的要求爲PNG的格式,那麼只壓縮輸出圖像爲jpeg這樣的:

outputBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);

這將在PNG使用硬件加速,而不是純軟件壓縮喜歡它顯着更快。整個操作時間約600毫秒,壓縮位需要約200毫秒。這是從前5秒使用PNG壓縮的非常巨大的改進。

從理論上講,如果您不關心透明度,您可以通過將Bitmap.Config.RGB_565用於輸出圖像而不是Bitmap.Config.ARGB_8888來獲得更高的性能。然而,在實踐中,我遇到兩個問題,阻止我這樣做:

  • 輸出圖像的顏色被弄亂。
  • 它實際上需要更長的時間來提取圖像。
相關問題