I am trying to use ExoPlayer, as opposed to MediaPlayer and I can't seem to figure it out...
MediaPlayer has .start() / .pause() commands... and I can just seekTo(1287) and it automatically starts playing...
How do I do this with ExoPlayer? I have tried to do seekTo(1287) but it doesn't start playing after... I have also added .setPlayWhenReady(true) after that, and still no luck...
I am able to .stop()... but I can't get it to start playing again after that unless I .prepare() again... but I don't think I should have to do that between every pause and play.
I am using my own controls and methods opposed to MediaController like in the ExoPlayer Demo... I can't quite see how the controls are implemented...
Any suggestions anyone?
Edit:
OK, I figured out pause and start...
.setPlayWhenReady(true) // start
.setPlayWhenReady(false) // pause
But I'm still having problems with the tracking... .seekTo works intermittently... sometimes it works... but other times I get this error:
E/AudioTrack: AudioTrack::set : Exit
(and it only gets to the buffer state... doesn't quite get to "ready"...
The official example of the PlayerControl in the ExoPlayer source code do exactly what you asked:
public class PlayerControl implements MediaPlayerControl {
private final ExoPlayer exoPlayer;
public PlayerControl(ExoPlayer exoPlayer) {
this.exoPlayer = exoPlayer;
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
throw new UnsupportedOperationException();
}
#Override
public int getBufferPercentage() {
return exoPlayer.getBufferedPercentage();
}
#Override
public int getCurrentPosition() {
return exoPlayer.getDuration() == ExoPlayer.UNKNOWN_TIME ? 0
: (int) exoPlayer.getCurrentPosition();
}
#Override
public int getDuration() {
return exoPlayer.getDuration() == ExoPlayer.UNKNOWN_TIME ? 0
: (int) exoPlayer.getDuration();
}
#Override
public boolean isPlaying() {
return exoPlayer.getPlayWhenReady();
}
#Override
public void start() {
exoPlayer.setPlayWhenReady(true);
}
#Override
public void pause() {
exoPlayer.setPlayWhenReady(false);
}
#Override
public void seekTo(int timeMillis) {
long seekPosition = exoPlayer.getDuration() == ExoPlayer.UNKNOWN_TIME ? 0
: Math.min(Math.max(0, timeMillis), getDuration());
exoPlayer.seekTo(seekPosition);
}
}
If you are experiencing strange behaviors during the seek operation, it may be due to you particular stream/file type. I can suggest you to take a look at the base implementation of the ExoPlayer and, eventually, report any issue on Github.
Here's how the example code does it for Exoplayer 2:
player.setPlayWhenReady(true);
starts playback, (false stops)
If the player is already in the ready state then this method can be used to pause and resume playback.
To seek, they use
boolean haveStartPosition = startWindow != C.INDEX_UNSET;
if (haveStartPosition) {
player.seekTo(startWindow, startPosition);
}
player.prepare(mediaSource, !haveStartPosition, false);
So it seems you need to prepare after the seekTo.
Related
I have a media player on one activity (called player) and I want to be able to support continuous video playback from when the player is closed into a miniature view on the parent activity.
I am able to do this just fine when it is audio only, the problem lies when I attach a SurfaceView via mediaPlayer.setDisplay();
I can attach the SurfaceView just fine initially but the problems start when I close the Player activity. If I make no changes, the mediaPlayer gets thrown into an error state somehow with the usual unhelpful errors (1, -19) etc.
I have tried using setDisplay(null) when the Player SurfaceView is destroyed which appears to work. But for some reason it resets the video stream. I've tried overriding seekTo() in order to figure out what is happening but seekTo() is not being called. I've also put logging statements everywhere I can think of but nothing is being triggered.
Why would setDisplay(null) cause my video stream to restart?
Here is my current MediaPlayer code (some of the weird stuff is from me trying to solve the issue (like isReallyPlaying()):
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private ScheduledFuture beeperhandle;
private boolean isPaused = false;
private BaseMedia currentMedia;
private PlaybackService.RepeatStatus repeatStatus = PlaybackService.RepeatStatus.REPEAT_NONE;
public void startMedia(BaseMedia model, Integer position) {
Timber.d("Starting media");
startBeeper();
isPaused = false;
lastBeep = -1;
currentMedia = model;
if (position != null) {
seekTo(position);
}
super.start();
}
public BaseMedia getCurrentMedia() {
return currentMedia;
}
#Override
public void start() throws IllegalStateException {
Timber.e("Invalid start called, should request startSong or startVideo");
}
private int lastBeep = -1;
// Because isPlaying is returning false and canceling the beeper. Probably has something to do with the surfaceview being destroyed
private boolean isStillPlaying() {
if (lastBeep != getCurrentPosition()) {
lastBeep = getCurrentPosition();
return true;
}
return false;
}
private final Runnable seekBarCheck = new Runnable() {
public void run() {
if (isStillPlaying() && !beeperhandle.isCancelled()) {
EventBus.getDefault().post(new MusicStatusTimeEvent(
currentMedia, true, GevaldMediaPlayer.this));
} else {
Timber.d("Canceling Beeper, !isPlaying");
beeperhandle.cancel(true);
}
}
};
private void startBeeper() {
Timber.d("Starting Beeper");
beeperhandle = scheduler.scheduleAtFixedRate(seekBarCheck, 100, 100, TimeUnit.MILLISECONDS);
}
#Override
public void seekTo(final int msec) throws IllegalStateException {
Timber.d("Seeking to " + msec);
if (beeperhandle != null) {
Timber.d("Canceling beeper in prep for seek");
beeperhandle.cancel(true);
}
setOnSeekCompleteListener(new OnSeekCompleteListener() {
#Override
public void onSeekComplete(MediaPlayer mp) {
Timber.d("Seek complete to: " + msec);
startBeeper();
}
});
super.seekTo(msec);
}
#Override
public void stop() throws IllegalStateException {
super.stop();
Timber.d("Stopping media");
doStop();
}
private void doStop() {
if (beeperhandle != null) {
Timber.d("Canceling beeper, doStop");
beeperhandle.cancel(true);
}
isPaused = false;
}
#Override
public void pause() throws IllegalStateException {
Timber.d("Pause requested");
if (beeperhandle != null) {
Timber.d("Canceling beeper, pause");
beeperhandle.cancel(true);
}
doStop();
EventBus.getDefault().post(new MusicStatusStoppedEvent(this));
super.pause();
}
public boolean isPaused() {
return isPaused;
}
Figured it out. Apparently closing an activity causes an audio loss with a value of AudioManager.AUDIOFOCUS_LOSS.
Since I was being a good Android citizen, that was set to release the media player. But audio would then be regained which would cause my media player to get reset and hence start from the beginning.
It just happened to line up that this occurred right around the setDisplay() method.
I have a problem that, after googling, I don't know why it is happenning.
I 've made and streaming video app with protocol RTSP. All is working good with a 3G/4G connection, but if i change to Wifi, much times video appears with a pixelation like a grey screen.
Testing in Android 5.1 (LG G3).
minSDKVersion = 15.
compiledSDKVersion = 22.
If i change to 3g, all goes well. It seems a problem of the initial buffer but its weird, because the problem is with Wifi connection (tested with two different connections, one xVDSL and one FTTH).
I'm not using any library, doing all the work directly with the android sdk and VideoView and mediaPlayer.
Here the code that init the configuration and how it handle the listeners:
videoView= (VideoView)this.findViewById(R.id.videoView);
videoView.setMediaController(null);
videoView.setOnErrorListener(this);
videoView.setOnCompletionListener(this);
videoView.setOnPreparedListener(this);
videoView.setVideoURI(Uri.parse(URL));
start/stop methods (the button above) and override listener methods:
public void startVideo(){
if(videoView !=null) {
initProgressDialog(getResources().getString(R.string.load_streaming));
startProgressDialog();
videoView.setVisibility(View.VISIBLE);
videoView.requestFocus();
//btnPlay.setVisibility(View.INVISIBLE);
}
}
public void stopVideo(){
if(videoView !=null) {
btnPlay.setText(getResources().getString(R.string.video_button_play));
stateVideo=2;
videoView.suspend();
}
}
public void resumeVideo(){
if(videoView !=null) {
initProgressDialog(getResources().getString(R.string.load_streaming));
startProgressDialog();
btnPlay.setText(getResources().getString(R.string.video_button_stop));
stateVideo=1;
videoView.setVisibility(View.VISIBLE);
videoView.resume();
}
}
private boolean manageErrorVideo(MediaPlayer mediaPlayer, int i, int i1){
return false;
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
videoView.setVisibility(View.VISIBLE);
stopProgressDialog();
}
#Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
//A lot of control error code. If need, ask but never go this way when the problem appear.
return true;
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
btnPlay.setText(getResources().getString(R.string.video_button_stop));
videoView.start();
stopProgressDialog();
stateVideo = 1;
findViewById(R.id.mainView).setBackgroundColor(Color.BLACK);
Log.d("test", mediaPlayer.getVideoHeight() + "");
Log.d("test", mediaPlayer.getVideoWidth()+"");
}
#Override
public boolean onInfo(MediaPlayer mediaPlayer, int i, int i1) {
return false;
}
#Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
}
Any information or help will be wellcome!
Thank you!!
EDIT: RTSP server is an IP camera.
I'm using MediaPlayer to play some recorded audio and SeekBar to show the progress of the play. My problem is: when I click on the SeekBar to jump to a time position the following example happens and i see on the Log when i want to see the progess:
getprogress(ms): 10000
getprogress(ms): 9956
getprogress(ms): 10000
So I jump to the recorded audio's 10th second. The MediaPlayer jumps to the 10th second but after It jumps back a bit as you can see.
I tried everything i could. I tried playing other recorder's audio files but happened the same. Tried playing with the bit rate and sampling rate but happened the same.
I hope someone knows the solution to this. Thank You.
Edit:
Code:
SeekBar:
progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
// handler2.removeCallbacks(updateTimeTask);
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (PlayerForegroundService.player != null) {
// handler2.removeCallbacks(updateTimeTask);
PlayerForegroundService.player.seekTo(seekBar.getProgress());
// handler2.post(updateTimeTask);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter(Constants.ACTION.PLAYER_UPDATE_UI));
}
}
});
}
getProgess():
public int getProgress(){
if ( player != null) {
Log.i(Constants.DEFAULTS.LOG_TAG, ""+player.getCurrentPosition());
return player.getCurrentPosition();
}
else
return 0;
}
The code when getProgress gets called:
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, final Intent intent) {
actPosition.setText(intent.getStringExtra("formattedtimeplay"));
progressBar.setProgress(PlayerForegroundService.player.getProgress());
if (intent.getBooleanExtra("pausedplay", false))
playButton.setImageResource(R.drawable.playfilled);
}
};
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter(Constants.ACTION.PLAYER_UPDATE_UI));
super.onCreate(savedInstanceState);
}
It seems i solved the problem. Before, I used to set the maximum value of the SeekBar in seconds. But after I set the max in milliseconds and the values of the seekTo in milliseconds it works fine.
I have a MediaPlayer in a Fragment which retains its instance on configuration changes. The player is playing a video loaded from my assets directory. I have the scenario set up with the goal of reproducing the YouTube app playback where the audio keeps playing during the configuration changes and the display is detached and reattached to the media player.
When I start the playback and rotate the device, the position jumps forward about 6 seconds and (necessarily) the audio cuts out when this happens. Afterwards, the playback continues normally. I have no idea what could be causing this to happen.
As requested, here is the code:
public class MainFragment extends Fragment implements SurfaceHolder.Callback, MediaController.MediaPlayerControl {
private static final String TAG = MainFragment.class.getSimpleName();
AssetFileDescriptor mVideoFd;
SurfaceView mSurfaceView;
MediaPlayer mMediaPlayer;
MediaController mMediaController;
boolean mPrepared;
boolean mShouldResumePlayback;
int mBufferingPercent;
SurfaceHolder mSurfaceHolder;
#Override
public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
super.onInflate(activity, attrs, savedInstanceState);
final String assetFileName = "test-video.mp4";
try {
mVideoFd = activity.getAssets().openFd(assetFileName);
} catch (IOException ioe) {
Log.e(TAG, "Can't open file " + assetFileName + "!");
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
// initialize the media player
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(mVideoFd.getFileDescriptor(), mVideoFd.getStartOffset(), mVideoFd.getLength());
} catch (IOException ioe) {
Log.e(TAG, "Unable to read video file when setting data source.");
throw new RuntimeException("Can't read assets file!");
}
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mPrepared = true;
}
});
mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
mBufferingPercent = percent;
}
});
mMediaPlayer.prepareAsync();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_main, container, false);
mSurfaceView = (SurfaceView) view.findViewById(R.id.surface);
mSurfaceView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mMediaController.show();
}
});
mSurfaceHolder = mSurfaceView.getHolder();
if (mSurfaceHolder == null) {
throw new RuntimeException("SufraceView's holder is null");
}
mSurfaceHolder.addCallback(this);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMediaController = new MediaController(getActivity());
mMediaController.setEnabled(false);
mMediaController.setMediaPlayer(this);
mMediaController.setAnchorView(view);
}
#Override
public void onResume() {
super.onResume();
if (mShouldResumePlayback) {
start();
} else {
mSurfaceView.post(new Runnable() {
#Override
public void run() {
mMediaController.show();
}
});
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaController.setEnabled(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// nothing
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mMediaPlayer.setDisplay(null);
}
#Override
public void onPause() {
if (mMediaPlayer.isPlaying() && !getActivity().isChangingConfigurations()) {
pause();
mShouldResumePlayback = true;
}
super.onPause();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
public void onDestroyView() {
mMediaController.setAnchorView(null);
mMediaController = null;
mMediaPlayer.setDisplay(null);
mSurfaceHolder.removeCallback(this);
mSurfaceHolder = null;
mSurfaceView = null;
super.onDestroyView();
}
#Override
public void onDestroy() {
mMediaPlayer.release();
mMediaPlayer = null;
try {
mVideoFd.close();
} catch (IOException ioe) {
Log.e(TAG, "Can't close asset file..", ioe);
}
mVideoFd = null;
super.onDestroy();
}
// MediaControler methods:
#Override
public void start() {
mMediaPlayer.start();
}
#Override
public void pause() {
mMediaPlayer.pause();
}
#Override
public int getDuration() {
return mMediaPlayer.getDuration();
}
#Override
public int getCurrentPosition() {
return mMediaPlayer.getCurrentPosition();
}
#Override
public void seekTo(int pos) {
mMediaPlayer.seekTo(pos);
}
#Override
public boolean isPlaying() {
return mMediaPlayer.isPlaying();
}
#Override
public int getBufferPercentage() {
return mBufferingPercent;
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
return mMediaPlayer.getAudioSessionId();
}
}
The if block in the onPause method is not being hit.
Update:
After doing a bit more debugging, removing the interaction with the SurfaceHolder causes the problem to go away. In other words, if I don't setDisplay on the MediaPlayer the audio will work fine during the configuration change: no pause, no skip. It would seem there is some timing issue with setting the display on the MediaPlayer that is confusing the player.
Additionally, I have found that you must hide() the MediaController before you remove it during the configuration change. This improves stability but does not fix the skipping issue.
Another update:
If you care, the Android media stack looks like this:
MediaPlayer.java
-> android_media_MediaPlayer.cpp
-> MediaPlayer.cpp
-> IMediaPlayer.cpp
-> MediaPlayerService.cpp
-> BnMediaPlayerService.cpp
-> IMediaPlayerService.cpp
-> *ConcreteMediaPlayer*
-> *BaseMediaPlayer* (Stagefright, NuPlayerDriver, Midi, etc)
-> *real MediaPlayerProxy* (AwesomePlayer, NuPlayer, etc)
-> *RealMediaPlayer* (AwesomePlayerSource, NuPlayerDecoder, etc)
-> Codec
-> HW/SW decoder
Upon examining AwesomePlayer, it appears this awesome player takes the liberty of pausing itself for you when you setSurface():
status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
mNativeWindow = native;
if (mVideoSource == NULL) {
return OK;
}
ALOGV("attempting to reconfigure to use new surface");
bool wasPlaying = (mFlags & PLAYING) != 0;
pause_l();
mVideoRenderer.clear();
shutdownVideoDecoder_l();
status_t err = initVideoDecoder();
if (err != OK) {
ALOGE("failed to reinstantiate video decoder after surface change.");
return err;
}
if (mLastVideoTimeUs >= 0) {
mSeeking = SEEK;
mSeekTimeUs = mLastVideoTimeUs;
modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
}
if (wasPlaying) {
play_l();
}
return OK;
}
This reveals that setting the surface will cause the player to destroy whatever surface was previously being used as well as the video decoder along with it. While setting a surface to null should not cause the audio to stop, setting it to a new surface requires the video decoder to be reinitialized and the player to seek to the current location in the video. By convention, seeking will never take you further than you request, that is, if you overshoot a keyframe when seeking, you should land on the frame you overshot (as opposed to the next one).
My hypothesis, then, is that the Android MediaPlayer does not honor this convention and jumps forward to the next keyframe when seeking. This, coupled with a video source that has sparse keyframes, could explain the jumping I am experiencing. I have not looked at AwesomePlayer's implementation of seek, though. It was mentioned to me that jumping to the next keyframe is something that needs to happen if your MediaPlayer is developed with streaming in mind since the stream can be discarded as soon as it has been consumed. Point being, it might not be that far fetch to think the MediaPlayer would choose to jump forward as opposed to backwards.
Final Update:
While I still don't know why the playback skips when attaching a new Surface as the display for a MediaPlayer, thanks to the accepted answer, I have gotten the playback to be seamless during rotation.
Thanks to natez0r's answer, I have managed to get the setup described working. However, I use a slightly different method. I'll detail it here for reference.
I have one Fragment which I flag to be retained on configuration changes. This fragment handles both the media playback (MediaPlayer), and the standard TextureView (which provides the SurfaceTexture where the video buffer gets dumped). I initialize the media playback only once my Activity has finished onResume() and once the SurfaceTexture is available. Instead of subclassing TextureView, I simply call setSurfaceTexture (since it's public) in my fragment once I receive a reference to the SurfaceTexture. The only two things retained when a configuration change happens are the MediaPlayer reference, and the SurfaceTexture reference.
I've uploaded the source of my sample project to Github. Feel free to take a look!
I know this question is a tad old now, but I was able to get this working in my app without the skipping. The issue is the surface getting destroyed (killing whatever buffer it had in it). This may not solve all your issues because it targets API 16, but you can manage your own SurfaceTexture inside your custom TextureView where the video is drawn:
private SurfaceTexture mTexture;
private TextureView.SurfaceTextureListener mSHCallback =
new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
int height) {
mTexture = surface;
mPlayer.setSurface(new Surface(mTexture));
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
int height) {
mTexture = surface;
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mTexture = surface;
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
mTexture = surface;
}
};
the key is returning false in onSurfaceTextureDestroyed and holding onto mTexture. When the view gets re-attached to the window you can set the surfaceTexture:
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mTexture != null) {
setSurfaceTexture(mTexture);
}
}
This allows my view to continue playing video from EXACTLY where it left off.
I'm trying to stream a video and play it using VideoView. I supply the view with the source URL of the video with setVideoURI() as shown below. With a hardcoded value like urlString = "www.myvideoserver.com/videos/bigbuckbunny.mp4", the video plays fine. However, when urlString is given the value from the intent (coming from the previous activity where the user chose the video), I get the message: "Sorry, Video cannot be played". I've read that one of the common causes is video format, like it's described here and here. I'm almost certain that it is not a format issue because I can play the video when the URL is fixed (and I know this because I can see from Log.d("PVurl", urlString); that the value of urlString is exactly the same as the one I fixed it to. That is, in LogCat, I copy paste the value into the line urlString = getIntent()... // "www.myvideoserver.com/videos/bigbuckbunny.mp4", and it works but not when urlString is set to the intent return value . LogCat Errror panel gives the following:
04-13 17:35:32.786: ERROR/MediaPlayer(2620): error (1, -1007)
04-13 17:35:32.786: ERROR/MediaPlayer(2620): Error (1,-1007)
I've searched around the internet but it doesn't seem that anyone has encountered such an error code before.
I'd very much appreciate if anyone has any idea what could be the problem. Thanks!
public void playvideo () { // obtain URL of the requested video from the intent in previous activity
try
{
urlString = getIntent().getStringExtra("mypackage.fulladdr");
if (urlStr != null)
{
Log.d("PVurl", urlString);
VideoView v = (VideoView) findViewById(R.id.videoView1);
// play video
v.setVideoURI(Uri.parse(urlString));
v.setMediaController(new MediaController(this));
v.start();
v.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
showRatingDialog();
}
});
}
}
catch (Exception e)
{
Log.d("PV_TAG", +e.getMessage());
e.printStackTrace();
}
}
You haven't added the scheme which the Uri needs to find out what it is referring to (http, in your case) .
urlString = "www.myvideoserver.com/videos/bigbuckbunny.mp4" change it to urlString = "http://www.myvideoserver.com/videos/bigbuckbunny.mp4"
(1, -1007) error means:
MEDIA_ERROR_UNKNOWN - "File or network related operation errors."
this may come from a corrupt file
see also javadoc of android.media.MediaPlayer.OnErrorListener#onError
http://developer.android.com/reference/android/media/MediaPlayer.OnErrorListener.html#onError
#param what the type of error that has occurred:
MEDIA_ERROR_UNKNOWN
MEDIA_ERROR_SERVER_DIED
#param extra an extra code, specific to the error. Typically implementation dependent.
MEDIA_ERROR_IO
MEDIA_ERROR_MALFORMED
MEDIA_ERROR_UNSUPPORTED
MEDIA_ERROR_TIMED_OUT
I tried the same thing and was able to get it to work. Perhaps something else is going on in your code. Here is what I have:
// Intent to start the activity that launches the video player
Intent i = new Intent(this, ExampleActivity.class);
i.putExtra("url", "http://www.yourvideo.com/yourvid.m4v");
startActivity(i);
And here is the code that deals with the player:
private MediaController mController;
private Uri videoUri;
private int percentBuffered= 0;
private VideoView videoView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
mController = new MediaController(this);
videoView = (VideoView) findViewById(R.id.videoView1);
// access String from the intent that launched this Activity
videoUri = Uri.parse(getIntent().getStringExtra("url"));
}
#Override
public void onResume() {
super.onResume();
videoView.setOnCompletionListener(this);
try {
videoView.setVideoURI(videoUri);
mController.setMediaPlayer(videoView);
videoView.setMediaController(mController);
videoView.requestFocus();
videoView.start();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onPause() {
super.onPause();
finish();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mController.show();
return super.onTouchEvent(event);
}
#Override
public int getBufferPercentage() {
return percentBuffered;
}
#Override
public int getCurrentPosition() {
return videoView.getCurrentPosition();
}
#Override
public int getDuration() {
return videoView.getDuration();
}
#Override
public boolean isPlaying() {
return videoView.isPlaying();
}
#Override
public void pause() {
videoView.pause();
}
#Override
public void seekTo(int pos) {
videoView.seekTo(pos);
}
#Override
public void start() {
videoView.start();
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
percentBuffered = percent;
}
#Override
public void onCompletion(MediaPlayer mp) {
}
public boolean canPause() {
return true;
}
public boolean canSeekBackward() {
return true;
}
public boolean canSeekForward() {
return true;
}
Alright, I found the problem after many futile hours of digging through to find what MediaPlayer error(1, -1007) means.
In reality, it has to do with the rather unfortunate fact that the line
getIntent().getStringExtra("mypackage.fulladdr");
returns a string with an extra white space at the end. I think it's an implementation issue with getIntent().
Anyone knows where to report these kind of bugs, that'd be great.
Thanks to #Akhil and #javaMe for their attempts!