githubのサンプルコードですが、MediaExtractorで再生~停止、シークは出来るのですが、ポーズ~再生が出来なくて困ってます。sdkにはそのようなコマンドもないみたいですし、どなたか分かるかたいませんでしょうか?
どうもextractorの内部時間が停止出来ないと、再生停止から再生を開始するとextractorの内部時間の位置まで早回し再生してしまうみたいで、困ってます。
以下サンプルです。
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.MediaController;
public class DecodePlayer extends Activity implements SurfaceHolder.Callback, MediaController.MediaPlayerControl {
private static String SAMPLE;
int select_position=0;
File outputFilename;
String outputFileStringName;
MediaFormat format;
String SrcPath;
private static final String TAG = "DecodeActivity";
private PlayerThread mPlayer = null;
private MediaController mediaController;
private long lastPresentationTimeUs;
private boolean seeked = false;
private long startMs;
private long startTime;
private long diff = 0;
private long lastSeekedTo = 0;
private long lastCorrectPresentationTimeUs = 0;
//ビューを重ねて表示するためのレイアウト
private FrameLayout mFrameLayout;
public static SurfaceHolder holder;
int play_start=1;
long offset=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//フルスクリーン表示にします
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
//タイトルバーを非表示にします
requestWindowFeature(Window.FEATURE_NO_TITLE);
Context context_app = this.getApplicationContext();
// スリープを無効に
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Configuration config = getResources().getConfiguration();
SurfaceView sv = new SurfaceView(this);
mediaController = new MediaController(this);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
linearLayout.addView(sv);
sv.getHolder().addCallback(this);
setContentView(linearLayout);
//ビデオソースパスをここで受け取る
Intent intent = getIntent();
SrcPath = intent.getStringExtra("SrcPath");
select_position=intent.getIntExtra("position", 0);
outputFilename=new File(SrcPath);
outputFileStringName=outputFilename.getName();
SAMPLE = SrcPath;
mediaController.setAnchorView(sv);
mediaController.setMediaPlayer(this);
}
protected void onDestroy() {
super.onDestroy();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mPlayer == null) {
final Handler h = new Handler();
h.post(new Runnable() {
@Override
public void run() {
try {
mediaController.show();
h.postDelayed(this, 2000);
} catch (Exception e) {
}
}
});
mPlayer = new PlayerThread(this, holder.getSurface());
mPlayer.start();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mPlayer != null) {
mPlayer.interrupt();
}
}
@Override
public void start() {
mPlayer.play();
}
@Override
public void pause() {
mPlayer.pause();
// mPlayer.stop();
}
@Override
public int getDuration() {
return (int) mPlayer.duration;
}
@Override
public int getCurrentPosition() {
return mPlayer.getCurrentPosition();
}
@Override
public void seekTo(int i) {
mPlayer.seekTo(i);
mediaController.show();
}
@Override
public boolean isPlaying() {
if (mPlayer != null)
return mPlayer.isPlaying();
else
return false;
}
@Override
public int getBufferPercentage() {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean canPause() {
return true; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean canSeekBackward() {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean canSeekForward() {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
private class PlayerThread extends Thread {
Handler handler = new Handler();
MediaController.MediaPlayerControl mediaPlayerControl;
Handler handler1 = new Handler();
long lastOffset = 0;
boolean isPlaying = false;
private MediaExtractor extractor;
private MediaCodec decoder;
private Surface surface;
private BufferInfo info;
private long duration;
private AudioTrack audioTrack;
public PlayerThread(MediaController.MediaPlayerControl mediaPlayerControl, Surface surface) {
this.surface = surface;
this.mediaPlayerControl = mediaPlayerControl;
}
@Override
public void run() {
MediaCodecPlay();
}
private void MediaCodecPlay() {
extractor = new MediaExtractor();
// extractor.setDataSource(SAMPLE);
File f = new File(SAMPLE);
FileInputStream fileIS = null;
FileDescriptor fd = null;
try {
fileIS = new FileInputStream(f);
fd = fileIS.getFD();
} catch (IOException e1) {
// TODO 自動生成された catch ブロック
e1.printStackTrace();
}
//extractor.setDataSource(fd, lastOffset, f.length());
extractor.setDataSource(fd, 0, f.length());
format = null;
for (int i = 0; i < extractor.getTrackCount(); i++) {
format = extractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
duration = format.getLong(MediaFormat.KEY_DURATION) / 1000;
if (mime.startsWith("video/")) {
extractor.selectTrack(i);
decoder = MediaCodec.createDecoderByType(mime);
decoder.configure(format, surface, null, 0);
break;
}
}
decoder.start();
ByteBuffer[] inputBuffers = decoder.getInputBuffers();
ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
info = new BufferInfo();
startMs = System.currentTimeMillis();
startTime=System.nanoTime()/1000;
boolean isEOS = false;
while (!Thread.interrupted())
{
if (!isEOS)
{
int inIndex = decoder.dequeueInputBuffer(1000);
if (inIndex >= 0) {
ByteBuffer buffer = inputBuffers[inIndex];
int sampleSize;
sampleSize = extractor.readSampleData(buffer, 0);
offset=offset+sampleSize;
if (sampleSize < 0) {
decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
}
else
{
if(play_start==1)
{
decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0);
//extractor.advance()で次のフレームをデコードするが、再生を停止させても内部の時間が進んでいくため、再生を開始すると早回しシークしてしまう??
extractor.advance();
}
else
{
//ここでポーズさせているが、再生開始時に最初から早回しシーク動作が入り20秒程度再生開始まで必要??
decoder.queueInputBuffer(inIndex, 0, 0,(int)( extractor.getSampleTime()), 0);
extractor.advance();
while(play_start==0)
{
}
}
}
}
}
int outIndex = decoder.dequeueOutputBuffer(info, 1000);
if (info.presentationTimeUs < lastPresentationTimeUs) { // correct timing playback issue for some videos
startMs = System.currentTimeMillis();
lastCorrectPresentationTimeUs = lastPresentationTimeUs;
}
switch (outIndex)
{
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
outputBuffers = decoder.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
break;
default:
ByteBuffer buffer = outputBuffers[outIndex];
lastPresentationTimeUs = info.presentationTimeUs;
if (seeked && Math.abs(info.presentationTimeUs / 1000 - lastOffset) < 100)
seeked = false;
while (!seeked && (info.presentationTimeUs / 1000 - lastOffset) > System.currentTimeMillis() - startMs)
{
try {
sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
decoder.releaseOutputBuffer(outIndex, true);
break;
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
break;
}
}
decoder.stop();
decoder.release();
extractor.release();
}
public int getCurrentPosition() {
if (info != null)
return (int) (info.presentationTimeUs / 1000);
else
return 0;
}
public void seekTo(int i) {
seeked = true;
extractor.seekTo(i * 1000, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
lastOffset = extractor.getSampleTime() / 1000;
startMs = System.currentTimeMillis();
diff = (lastOffset - lastPresentationTimeUs / 1000);
}
public void pause() {
play_start=0;
isPlaying = false;
}
public void play() {
play_start=1;
isPlaying = true;
}
public boolean isPlaying() {
return isPlaying;
}
}
}