我正在尝试从库中播放 .mp4 格式的视频,并在相机应用程序中录制视频。当我尝试执行 setDisplay 时,出现表面已释放错误。我已经阅读了大多数论坛,我确信这是我处理我的 surfaceView 或我的持有者的方式。在我调用我的开始之前,我的表面总是被破坏,我不知道如何保持它的创建。需要社区建议,因为这是我第一次这样做
我知道它正确地获取了文件的路径,并且当我删除任何播放视频的尝试时,音频部分起作用了。也许这与我在启动应用程序时看到主屏幕上的表面有关,所以我的 XML 可能不正确,但我认为应该没问题:
public class MainActivity extends Activity implements OnClickListener,
OnPreparedListener, OnCompletionListener, SurfaceHolder.Callback,
OnBufferingUpdateListener, OnVideoSizeChangedListener {
private static final int SELECT_VIDEO = 1;
private static final String TAG = "MainActivity";
private byte[] videoFile;
private int mVideoWidth;
private int mVideoHeight;
private MediaPlayer mMediaPlayer;
private SurfaceView mPreview;
private SurfaceHolder holder;
private Bundle extras;
private boolean mIsVideoSizeKnown = false;
private boolean mIsVideoReadyToBePlayed = false;
private boolean hasActiveHolder = false;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPreview = (SurfaceView) findViewById(R.id.surface);
holder = mPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
extras = getIntent().getExtras();
setupButtonClickListeners();
}
private void setupButtonClickListeners() {
Button exitButton = (Button) findViewById(R.id.exitButton);
exitButton.setOnClickListener(this);
Button selectVideoButton = (Button) findViewById(R.id.selectVideo);
selectVideoButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.exitButton:
this.finish();
break;
case R.id.selectVideo:
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(
Intent.createChooser(intent, "Select Video"), SELECT_VIDEO);
break;
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case SELECT_VIDEO:
doCleanUp();
Uri videoUri = data.getData();
String path = getPath(videoUri);
boolean success = readFromFile(path);
if (success) {
// Create a new media player and set the listeners
playVideo(path);
} else {
//do nothing for now
}
Log.i(TAG, path);
break;
}
}
}
private void playVideo(String path) {
try {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(path);
// Here is the problem
synchronized (this) {
while (!hasActiveHolder) {
try {
this.wait();
} catch (InterruptedException e) {
//Print something
}
}
}
mMediaPlayer.setDisplay(holder);
mMediaPlayer.prepare();
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnVideoSizeChangedListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
} catch (Exception ex) {
Log.e(TAG, "error: " + ex.getMessage(), ex);
}
}
private void doCleanUp() {
mVideoWidth = 0;
mVideoHeight = 0;
mIsVideoReadyToBePlayed = false;
mIsVideoSizeKnown = false;
}
private boolean readFromFile(String path) {
File file = new File(path);
try {
FileInputStream fis = new FileInputStream(file);
Log.i(TAG, "File Size: " + file.length());
videoFile = new byte[(int) file.length()];
fis.read(videoFile);
fis.close();
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
return true;
}
@SuppressWarnings("deprecation")
private String getPath(Uri uri) {
String[] projection = { MediaStore.Video.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndex(MediaStore.Video.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
Log.d(TAG, "onPrepared called");
mIsVideoReadyToBePlayed = true;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
@Override
public void onCompletion(MediaPlayer mp) {
Log.d(TAG, "onCompletion called");
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
Log.d(TAG, "surfaceChanged called");
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
Log.d(TAG, "surfaceCreated called");
synchronized (this) {
hasActiveHolder = true;
this.notifyAll();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.d(TAG, "surfaceDestroyed called");
synchronized (this) {
hasActiveHolder = false;
this.notifyAll();
}
}
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
Log.v(TAG, "onVideoSizeChanged called");
mIsVideoSizeKnown = true;
mVideoWidth = width;
mVideoHeight = height;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
private void startVideoPlayback() {
Log.v(TAG, "startVideoPlayback");
holder.setFixedSize(mVideoWidth, mVideoHeight);
mMediaPlayer.start();
}
@Override
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
Log.d(TAG, "onBufferingUpdate percent:" + percent);
}
@Override
protected void onPause() {
super.onPause();
releaseMediaPlayer();
doCleanUp();
}
@Override
protected void onDestroy() {
super.onDestroy();
releaseMediaPlayer();
doCleanUp();
}
private void releaseMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
}
}
我的表面 XML 如下。再一次,不知道为什么在应用程序加载时会显示表面,但我只想在从图库中选择视频后在那里播放。:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<android.view.SurfaceView
android:id="@+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<Button
android:id="@+id/changeFilePath"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="78dp"
android:text="@string/changeFilePath" />
<Button
android:id="@+id/recordVideo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/changeFilePath"
android:layout_centerHorizontal="true"
android:text="@string/recordVideo" />
<Button
android:id="@+id/exitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/recordVideo"
android:layout_centerHorizontal="true"
android:layout_marginTop="49dp"
android:text="@string/exitButton" />
<Button
android:id="@+id/selectVideo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/recordVideo"
android:layout_centerHorizontal="true"
android:text="@string/selectVideo" />
</RelativeLayout>