I'm trying to play a video from Android using a SurfaceView
.
I can load the video, the sound is played correctly but I can't see the video.
Here is my activity :
public class VideoTest extends Activity implements OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback, OnErrorListener {
private static final String TAG = "MediaPlayerDemo";
private int mVideoWidth;
private int mVideoHeight;
private MediaPlayer mMediaPlayer;
private SurfaceView mPreview;
private SurfaceHolder holder;
private String path;
private Bundle extras;
public static final String MEDIA = "media";
private static final int LOCAL_AUDIO = 1;
public static final int STREAM_AUDIO = 2;
private static final int RESOURCES_AUDIO = 3;
private static final int LOCAL_VIDEO = 4;
public static final int STREAM_VIDEO = 5;
private boolean mIsVideoSizeKnown = false;
private boolean mIsVideoReadyToBePlayed = false;
private RelativeLayout layout;
/**
*
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mPreview = new SurfaceView(this);
holder = mPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
extras = getIntent().getExtras();
mPreview.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
layout = new RelativeLayout(this);
layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
layout.addView(mPreview, 0);
setContentView(layout);
}
private void playVideo(Integer Media) {
doCleanUp();
try {
mMediaPlayer = MediaPlayer.create(this, R.raw.video);
mMediaPlayer.setDisplay(holder);
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnVideoSizeChangedListener(this);
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
} catch (Exception e) {
Log.e(TAG, "error: " + e.getMessage(), e);
}
}
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
Log.d(TAG, "onBufferingUpdate percent:" + percent + " pos : " + mMediaPlayer.getCurrentPosition() + " / " + mMediaPlayer.getDuration());
if (mMediaPlayer.isPlaying()) {
Log.d(TAG, "Playing");
} else {
mMediaPlayer.start();
}
}
public void onCompletion(MediaPlayer arg0) {
Log.d(TAG, "onCompletion called");
}
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
Log.v(TAG, "onVideoSizeChanged called");
if (width == 0 || height == 0) {
Log.e(TAG, "invalid video width(" + width + ") or height(" + height
+ ")");
return;
}
mIsVideoSizeKnown = true;
mVideoWidth = width;
mVideoHeight = height;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
public void onPrepared(MediaPlayer mediaplayer) {
Log.d(TAG, "onPrepared called");
mIsVideoReadyToBePlayed = true;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) {
Log.d(TAG, "surfaceChanged called. Width : " + j + ", height : " + k);
holder = surfaceholder;
mMediaPlayer.setDisplay(holder);
mIsVideoSizeKnown = true;
mVideoWidth = j;
mVideoHeight = k;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
public void surfaceDestroyed(SurfaceHolder surfaceholder) {
Log.d(TAG, "surfaceDestroyed called");
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated called");
playVideo(extras.getInt(MEDIA));
}
@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;
}
}
private void doCleanUp() {
mVideoWidth = 0;
mVideoHeight = 0;
mIsVideoReadyToBePlayed = false;
mIsVideoSizeKnown = false;
}
private void startVideoPlayback() {
Log.v(TAG, "startVideoPlayback " + mVideoWidth + "x" + mVideoHeight);
int width = mPreview.getWidth();
int height = mPreview.getHeight();
float boxWidth = width;
float boxHeight = height;
float videoWidth = mMediaPlayer.getVideoWidth();
float videoHeight = mMediaPlayer.getVideoHeight();
Log.i(TAG, String.format("startVideoPlayback @ video %dx%d - box %dx%d", (int) videoWidth, (int) videoHeight, width, height));
float wr = boxWidth / videoWidth;
float hr = boxHeight / videoHeight;
float ar = videoWidth / videoHeight;
if (wr > hr) {
width = (int) (boxHeight * ar);
} else {
height = (int) (boxWidth / ar);
}
Log.i(TAG, String.format("Scaled to %dx%d", width, height));
holder.setFixedSize(width, height);
mMediaPlayer.start();
}
public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
Log.e(TAG, "ERROR called : " + arg1 + ", " + arg2);
return false;
}
}
The onVideoSizeChanged
function is never called but the onPrepared
and surfaceChanged
are called.
Thus the startVideoPlayback
function is called, but the video width and height are 0.
My video is playing, as I can hear the sound, but nothing is displayed on the screen.
I also tried to give raw width and height to the setFixedSize
function of the SurfaceHolder
object but I still don't have anything displayed.
Can you help me? I'm using Android 8
EDIT
Here is the log I have when I'm playing a video from the resources :
WARN info/warning (1, 35)
WARN info/warning (1, 44)
DEBUG Duration : 101248
DEBUG surfaceChanged called. Width : 480, height : 270
INFO Info (1,35)
INFO Info (1,44)
DEBUG onPrepared called
VERBOSE startVideoPlayback 480x270
INFO startVideoPlayback @ video 0x0 - box 480x270
INFO Scaled to 480x0
DEBUG surfaceDestroyed called
EDIT 2
I tried with another video and it's working.
Here are the specifications of the "not working" video :
- Container : MP4 - QuickTime
- Rate : 2 340 Kbps
- Format : H.264/MPEG-4-AVC
- Size : 1280*640
- Aspect pixel : undefined
- Image proportion : 2.000
- Encoding profile : [email protected]
Here are the specifications for the working video :
- Container : MP4 - QuickTime
- Rate : 537 Kbps
- Format : H.264/MPEG-4-AVC
- Size : 640*360
- Aspect pixel : undefined
- Image proportion : 16:9
- Encoding profile : [email protected]
Do you know what's wrong with the first video ?
MediaCodec
API instead so the videos can play regardless of the resolution. My gut feeling is due to the size of the video. When you changed the resolution for the second video, it worked because it can comfortably fit on the screen. – rayryeng