簡體   English   中英

Android MediaCodec解碼器:放慢視頻播放

[英]Android MediaCodec Decoder: Slow Down Video Playback

我已經搜索過,但仍然找不到答案。

我正在使用API​​ 21中的androids MediaCodec(使用解碼器和Surface)制作一個簡單的視頻播放器。但是,視頻播放非常快。 如何以正常速度播放視頻?

這是我的代碼:

 package com.bd.mediacodec; import java.io.IOException; import java.nio.ByteBuffer; import android.app.Activity; import android.media.MediaCodec; import android.media.MediaCodec.BufferInfo; import android.media.MediaCodec.CodecException; import android.media.MediaExtractor; import android.media.MediaFormat; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; public class DecodeActivity extends Activity implements SurfaceHolder.Callback { private static final String SAMPLE = Environment.getExternalStorageDirectory() + "/video.mp4"; private Surface surface; private MediaExtractor extractor; private MediaCodec decoder; boolean isEOS = false; long extractorSampleTime = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SurfaceView sv = new SurfaceView(this); sv.getHolder().addCallback(this); setContentView(sv); } protected void onDestroy() { super.onDestroy(); } @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { extractor = new MediaExtractor(); try { extractor.setDataSource(SAMPLE); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } for (int i = 0; i < extractor.getTrackCount(); i++) { MediaFormat mediaFormat = extractor.getTrackFormat(i); String mime = mediaFormat.getString(MediaFormat.KEY_MIME); if (mime.startsWith("video/")) { extractor.selectTrack(i); try { decoder = MediaCodec.createDecoderByType(mime); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } surface = holder.getSurface(); decoder.configure(mediaFormat, surface, null, 0); break; } } if (decoder == null) { Log.e("DecodeActivity", "Can't find / Open Video"); return; } // Adding Callback decoder.setCallback(mDecoderCallback); decoder.start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); decoder.stop(); decoder.release(); extractor.release(); } MediaCodec.Callback mDecoderCallback = new MediaCodec.Callback() { @Override public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) { // TODO Auto-generated method stub } @Override public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) { // TODO Auto-generated method stub // Release output buffer. codec.releaseOutputBuffer(index, true); } @Override public void onInputBufferAvailable(MediaCodec codec, int index) { // TODO Auto-generated method stub if(!isEOS){ ByteBuffer buffer = codec.getInputBuffer(index); int sampleSize = extractor.readSampleData(buffer, 0); if (sampleSize < 0) { Log.d("DecodeActivity", "InputBuffer BUFFER_FLAG_END_OF_STREAM"); decoder.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); isEOS = true; } else { extractorSampleTime = extractor.getSampleTime(); decoder.queueInputBuffer(index, 0, sampleSize, extractorSampleTime, 0); extractor.advance(); } } } @Override public void onError(MediaCodec codec, CodecException e) { // TODO Auto-generated method stub } }; } 

Grafika中有一對簡單的視頻播放 ,一個用於SurfaceView,一個用於TextureView。 它們都使用SpeedControlCallback類來管理播放速度。 關鍵是使用每個幀的演示時間戳記來確定顯示下一幀之前要等待多長時間。

僅當視頻使用固定幀速率時,才將播放速度使用固定值才有意義。 有關可變幀率視頻的示例,請參見Grafika中生成的電影。 其中一個播放器具有“以60fps播放”按鈕,該按鈕使播放器忽略時間戳,因此您可以觀察到差異。

順便說一句,將播放循環放在surfaceChanged()中不是一個好主意。 使用回調觸發活動,不要在其中建立整個播放器。

找到了解決方案。 不知道這是否是最佳解決方案。

mediaFormat ,我提取了captureRate

captureRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE);

然后,

  @Override public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) { // TODO Auto-generated method stub // Release output buffer. codec.releaseOutputBuffer(index, true); try { Thread.sleep((int)1000/captureRate); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM