2016-08-19 115 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来获得更高的性能。然而,在实践中,我遇到两个问题,阻止我这样做:

  • 输出图像的颜色被弄乱。
  • 它实际上需要更长的时间来提取图像。
相关问题