I researched a little bit, but couldn't find any solutions to this problem:
I would like to play a MediaPlayer and pause/stop it at a given time.. (ie: play from second 6 to second 17).
I know that I can set its starting point with seekTo() method, but can I pause/stop it from playing by setting an end point (of course, before reaching the file end limit)?
There are different ways you could do this, here's one:
int startFrom = 6000;
int endAt = 11000;
MediaPlayer mp;
Runnable stopPlayerTask = new Runnable(){
#Override
public void run() {
mp.pause();
}};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mp = MediaPlayer.create(this, R.raw.my_sound_file);
mp.seekTo(startFrom);
mp.start();
Handler handler = new Handler();
handler.postDelayed(stopPlayerTask, endAt);
}
The mediaplayer will start playing 6 seconds in and pause it 11 seconds after that (at second 17).
I think you can create Timer and call seekTo() directly from its task. Then call stop()/pause() inside of that Timer Task.
Maybe this post will be helpfull for you.
Or you can use handler for this task, like Ken Wolf shows you.
Best wishes.
You can use CountDownTimer
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
mp.stop;
mp.relese();
}
}.start();
I know this already has an answer but here is an alternative for anyone wanting to do this efficiently for a video with controls.
I saw a different answer that involved constantly checking the position.
Note that this assumes that you do not need a lot of different portions of one video. Even in that case I suggest to follow the below.
If you only need to play a portion of the video and want it to end somewhere, then why not just use free video editing software and clip the end? You can still start it from anywhere using seekTo() but this way you don't have to waste resources checking for a certain position (video with controls).
If you do not have video player controls the accepted answer will work. But if you do have player controls then it would not since a user could pause and play the video.
There's a time difference between videoView.start() and video prepared to play depend on video format, those time difference is probably more than 10 frames.
so the best way to do is to start the timer inside OnPreparedListener to minimise the time difference, or even more to get the current playing duration and set a postDelayed timer at that point.
Related
I am learning to code for Android and I have a problem with... maybe performance?
I want to play very short sound every second. I have created a CountDownTimer (with tick interval 20ms so very accurate) and putted there in onTick to play it. But the sound is played not precisely after one second and I can hear this - this is the problem...
fragment of my code:
private class ExerciseCountDownTimer extends CountDownTimer
{
...
public void onTick(long millisUntilFinished)
{
...
if(/*this is a next second not just a tick*/)
playSound(R.raw.quick_rest, true);
}
}
private void playSound(int resId, boolean releaseAfter)
{
if (currentMediaPlayerRes != resId || mediaPlayer == null)
{
if (mediaPlayer != null)
{
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
}
currentMediaPlayerRes = resId;
mediaPlayer = MediaPlayer.create(this, resId);
if (releaseAfter)
{
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mp)
{
mediaPlayer.release();
mediaPlayer = null;
}
});
}
}
mediaPlayer.start();
}
Is it possible to have counter like this?
use this code to play a music one time
MediaPlayer AlarmMusic;
AlarmMusic = MediaPlayer.create(G.context, R.raw.music1);
AlarmMusic.setLooping(false);
AlarmMusic.start();
this worked for me !
Because of the lack of real time guarantees in Java/Android, using one thread to cue another probably will always have some inaccuracy.
I can think of two approaches that might work for you:
(1) make the sound file exactly 1 second long, e.g., 44100 frames at 44100 fps, if you are using the standard "CD-quality" format that Java supports. The sound file can probably be edited with Audacity to an exact frame length. Then, use a looping playback.
(2) Open a line for streaming audio. I can't recall exactly what the Android-supported command is for this, but I know it exists. With it, count elapsing frames while sending silence (bytes with 0 value). When you get to the 44100th frame, start feeding the PCM data that you wish to hear. When it is done, go back to feeding 0's until the next 44100 frame arrives. Never stop the line--keep it running in its own thread, probably with a high priority. It is generally okay to give audio a high priority (as long as you are doing nothing else on the line) as audio spends a vast majority of its time in a "blocked" state during which it is yielding to other lines.
A fellow on java-gaming.org made a metronome and got it working on Android. I bet if you search for "metronome" on that site, his thread will pop up and have some useful info. He basically used the second approach that I described above.
I am trying to Seek to a particular location in a video in Android and I am completely stuck because of the inconsistencies it is showing in its behaviour. Here's a list of things I ve done
VideoView.Seekto goes to 5:19 for one video, 5:17 for one video and 5:32 for another for the same milliseconds(326000 ms)!
Since VideoView does not support onSeekListener, I've modified the
source VideoView and added support for it. Yet it does not pause and
start seeking from where I want it to - there is always a lag! The
onSeekListener is called immediately some 6 s before where I want it
to stop. In many cases the seek bar shows the right time and suddenly jumps back a few seconds even though I am calling video.start
from onSeekCompleteListener
Why is this so inconsistent ? Is there a definite way of seeking to where you want to go in milliseconds in videoview? I know I should use MediaPLayer + Surface but since VideoView is just a wrapper of the two I am modifying it at source but to no avail.
I am aware of this : http://code.google.com/p/android/issues/detail?id=9135
But is there any way to get around this and have a definite way of
1.) Seeking to the exact time in milliseconds
2.) Pausing and resuming at the exact time?
You have to wait for the seeking to complete.
VideoView does not have a OnSeekCompleteListener() but you can access the MediaPlayer from the onPrepared method of the VideoView and then set the OnSeekCompleteListener, like this :
videoView.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setOnSeekCompleteListener(new OnSeekCompleteListener() {
#Override
public void onSeekComplete(MediaPlayer mp) {
//Seek completed. Move seekbar
}
});
}
});
10 years later and I came across the same question exactly.
Any way, for me, the solution was to use the mediaPlayer from inside VideoView (Android Oreo 8.0+):
Explanation:
videoView default seekTo function use mediaPlayer default seekTo function (source)
mediaPlayer default seekTo overload is the same as seekTo(long, int) with SEEK_PREVIOUS_SYNC mode, you should use SEEK_PREVIOUS_SYNC only if you want to seek to a sync frame that has a timestamp earlier than or the same as milliseconds given,
However, SEEK_CLOSEST will seek to a frame that may or may not be a sync frame but is closest to or the same as milliseconds.
I know this is not the proper solution to your question but take a look into this library that is being made over the Google's default video view
https://github.com/brianwernick/ExoMedia
It has all the functionality and more that is being supported by default video view.
You can use this video view and emVideoView.seekTo(1000); to jump to 1000 millisecond in the video. You can also have setOnSeekCompletionListener to do process when seek complete.
I solved this problem like this
the seekTo() function doesn't work in VideoView
I am writing an android game for teaching kids to count. The instructions are read to the player through sound clips that are put together to form sentences (for instance "Place", "one", "cow", "in the", "barn". This requires a certain amount of reliability when it comes to latency so that the flow of the instructions sounds natural.
Currently I am using MediaPlayer, playing each sound in a OnCompletionListener. Each sound has it's own MediaPlayer that is created and prepared before playback of any sound starts (to reduce latency) - but still I get a significant delay before each sound the first time it is played (the second time it seems some sort of caching has taken place and it works fine).
The sounds are not many and very short and it should probably work better with SoundPool, but SoundPool has no way of knowing when an audio is complete and thus not an option.
Does anyone have any experience with similar problems and a viable solution?
I have used handler with OnCompletionListener and it worked fine for me to give delay between two sounds.
this way,
CommonMethod.player.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
// /will use count and loop as per number of
// repetition chosen.
handler.postDelayed(new Runnable() {
public void run() {
if (counter >= limit) {
CommonMethod.player.stop();
} else {
CommonMethod.player.start();
}
counter++;
}
}, 3000);
}
});
I am using VideoView to play *.mp4 file. And I want to play and pause it at a specific time.
Here is my code:
VideoView videoView=(VideoView)findViewById(R.id.video_view);
videoView.setVideoURI(Uri.parse("/sdcard/video/myvideo.mp4"));
videoView.seekTo(15000);
videoView.play();
In this case, video start from 00:00:15. And I want to pause it at 00:00:30.
How to do that?
final VideoView videoView=(VideoView)findViewById(R.id.video_view);
videoView.postDelayed(new Runnable() {
#Override
public void run() {
videoView.pause();
}
}, 15000);
If you want the video to pause at exactly 00:00:30 and not just 30 sec after video play, the most reliable way is to have a handler that run every second to check on the current position of the video. Pause the video if the current position is equal or larger than 30 sec.
I can play the videos fine back to back by implementing the OnCompletionListener to set the data source to a different file. No problems there. I call reset() and prepare() just fine.
What I haven't been able to figure out, is how to get rid of the 1-2 second gap screen flicker between the data source change and the new video starting. The gap shows a black screen, and I haven't found any way to get around it.
I've tried setting the background of the parent view to an image, but it manages to bypass that. Even if the SurfaceView is transparent (which it is by default.) I've also tried to have the multiple video files played at the same time, and switching mediaplayer's display when one ends and the other is supposed to start.
The last thing I tried, was to have a second view in the background that I show temporarily while the video is "preparing" and removing it when the video is ready to start. That also wasn't very seamless.
Is there any way to get rid of that gap. Running a video in a loop works wonderfully and does exactly what I want with the exception that it's looking through the same video instead of playing a different one that I pick.
main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:background="#drawable/background"
android:layout_height="fill_parent">
<SurfaceView
android:id="#+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center">
</SurfaceView>
</FrameLayout>
Player.java
public class Player extends Activity implements
OnCompletionListener, MediaPlayer.OnPreparedListener, SurfaceHolder.Callback {
private MediaPlayer player;
private SurfaceView surface;
private SurfaceHolder holder;
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.main);
surface = (SurfaceView)findViewById(R.id.surface);
holder = surface.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void onCompletion(MediaPlayer arg0) {
File clip = new File(Environment.getExternalStorageDirectory(),"file2.mp4");
playVideo(clip.getAbsolutePath());
}
public void onPrepared(MediaPlayer mediaplayer) {
holder.setFixedSize(player.getVideoWidth(), player.getVideoHeight());
player.start();
}
private void playVideo(String url) {
try {
File clip = new File(Environment.getExternalStorageDirectory(),"file1.mp4");
if (player == null) {
player = new MediaPlayer();
player.setScreenOnWhilePlaying(true);
}
else {
player.stop();
player.reset();
}
player.setDataSource(url);
player.setDisplay(holder);
player.setOnPreparedListener(this);
player.prepare();
player.setOnCompletionListener(this);
}
catch (Throwable t) {
Log.e("ERROR", "Exception Error", t);
}
}
I too have the same problem as outlined by below link
VideoView Disappears for a second when video is changed
But this issue wont occur if you try using Android 4.0+ (ICS). I started to port VideoView.java and MediaPlayer.java from 4.0 to my app , but thats seems complex and no luck till now. Basically it seems a bug in the native code of the older versions.
after too much wasted time trying to figure out how to play consecutive videos without the "gap", i'm leaning towards impossible. unless of course you're able to dig down to the native level and implement your own player, Android's media player simply doesn't support seamless playback as of the moment.
I've not done this with video playback on a MediaPlayer but I've done something similar with audio files when a stream gets interrupted because a user has switched from 3G to Wifi.
I think the delay that you're seeing is whilst the media player is buffering the input file.
So maybe you can define both players at the start? You should do define the datasource and prepare both players but only start one of them.
Then in your onCompletionListener you can flip them over instead of resetting the existing one and setting a new datasource.
player.release();
player = flipPlayer;
flipPlayer = null;
player.start();
Obviously you'd need to either use a different onPreparedListener for flipPlayer or take the player.start() out of the onPrepare. (Since you're calling it synchronously I wouldn't have thought this was an issue).
I don't think it's possible.
Reason: Mortplayer was also available for windows mobile and one of its strengths was that it supported gapless play. However it doesn't in the android version of the app, and the developer itself writes that the SDK does not allow it on xda:
http://forum.xda-developers.com/showpost.php?p=5364530&postcount=5
HTH, Daniele
Did you try to have ready (opened/prepared) 2 VideoView's, with one being visible, other invisible and stopped, and ass soon you get OnCompletionListener callback, make 2nd one visible, start it, and hide 1st one.
In meantime, as 2nd one plays, you can call open/prepare on 1st VideoView to open/prepare another file.
#user1263019 - were you able to port Android 4.0 MediaPlayer to your app? I'm facing the same issue and I'm looking for a nice solution. My case is having an image over the SurfaceView which should be hidden in order to show the video playing, but there is a gap between calling start() and the actual start of the video. The only solution so far is to start a Thread that checks if getCurrentPosition() is > 0.
On the topic - I think it is not possible to have gapless playback, though Winamp claim to have such abilities. A dirty hack is to prepare the second player several seconds before the end of the playback of the first player and then call start() of the second player 100-200ms before end of playback.
In your exoplayer implementation (or mediaplayer) use a handler to repeatedly post a runnable, while playing, that gets the current tracking time and passes it to a callback:
public interface MediaAction {
public void onTrackingChanged(long currentPosition);
}
public class ExoPlayerImplementation implements Exoplayer {
..
private MediaAction mediaActionCallback;
public void setMediaActionCallback(MediaAction ma) {
mediaActionCallback = ma;
}
public void releaseMediaAction() { mediaActionCallback = null; }
private Handler trackingCallback = new Handler(Looper.getMainLooper());
Runnable trackingTask;
private Runnable getTrackingTask() {
Runnable r = new Runnable {
#Override public void run() {
long currentPosition = getCurrentPosition();
if (mediaActionCallback != null) {
mediaActionCallback.onTrackingChanged(currentPosition);
}
// 60hz is 16 ms frame delay...
trackingCallback.postDelayed(getTrackingTask(), 15);
}
};
trackingTask = r;
return r;
}
public void play() {
// exoplayer start code
trackingCallback.post(getTrackingTask());
}
public void pause/stop() {
trackingCallback.removeCallbacks(trackingTask);
}
..
}
And now you can track when the current position actually has changed--if it has changed, then you can show your video output view / swap views / remove preview (ie, use MediaExtractor to grab initial frames, overlay as preview in an ImageView then hide once current position is increasing). You can make this code more complete by combining it with the state listener: then you know if you are buffering (check buffering position versus current position), actually playing, paused or stopped with proper callbacks (in MediaAction). You can apply this method to both MediaPlayer and ExoPlayer classes (since it is just an interface and handler).
Hope that helps!