I have a ViewPager with items extending from FrameLayout, each one of them represents a video. Code for initialization:
try {
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setDataSource(getContext(), Uri.parse(mVideo.getVideo().getPreviewMedium().getUrl()));
mPlayer.setOnPreparedListener(mOnPreparedListener);
mPlayer.prepareAsync();
} catch (Exception e) {
LOG.toLog(e);
}
And in onPrepared :
mPlayer.start();
As i know, ViewPager is trying to initialize 3 items : current, previous and next, so if i'm switching between these 3 it works fine, but if i'm going further and then reurning back - video is loading again after mPlayer.setDataSource
Question: Is there any chance to cache it after first setup, so future calls of mPlayer.setDataSource will work instantly?
viewpager.setoffsetlimit() to the size of you item.
Use is prepared to check if is prepared.If it's prepared , you neednt't setData.
Related
I am using ExoPlayer for playing video in loop, but before source video is started each loop I need to reset some states of my Layout. I know ExoPlayer is calling onPlayerStateChanged with ExoPlayer.STATE_ENDED paramter when video is ended for usual MediaSources, but it is not called for LoopingMediaSource.
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == ExoPlayer.STATE_ENDED) {
showControls();
resetLayoutStates(); //I need it here, even in LoopingMediaSource
}
updateButtonVisibilities();
}
Does the Exoplayer have any Callback when Source is restarted or ended in loop ? Or does it have any workaround for my situation ?
You can detect that a video loops when the media item changes. This callback will be fired at the end of the media item and give you the new item to play even if that's the same when repeat mode is ONE. You can detect that with the reason parameter that tells you why the media changed (either naturally, seeking or looping):
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
super.onMediaItemTransition(mediaItem, reason)
if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_REPEAT) {
// Reset your state
}
}
You may want to assert that it's the right media item with the given mediaItem argument. Especially since it will behave differently whether your repeat mode is ONE or ALL (the media item will be the same for ONE while the first or last item of your timeline for ALL).
I have a custom view (a button) and I want it to have a certain sound when pressed.
private void playSound() {
if (mediaPlayer == null)
initMediaPlayer();
try {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
private void initMediaPlayer() {
try {
AssetFileDescriptor afd = getContext().getAssets().openFd("music/number_tap.m4a");
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
} catch (IOException e) {
e.printStackTrace();
}
}
I call the playSound method every time the button is clicked. It works well as long as there is only one button on screen. No problem at all.
It crashes if I have more buttons on the screen and I press the first button a couple of times (works) and then some other button 2 times (crashes on the second press of the second button).
Any idea what could be wrong? Here's the crash stacktrace.
FATAL EXCEPTION: main
Process: com.matejhacin.multiflow, PID: 20991
java.lang.IllegalStateException
at android.media.MediaPlayer._prepare(Native Method)
at android.media.MediaPlayer.prepare(MediaPlayer.java:1163)
at com.matejhacin.multiflow.views.KeyButtonView.playSound(KeyButtonView.java:126)
at com.matejhacin.multiflow.views.KeyButtonView.onTouch(KeyButtonView.java:77)
From what I can see, you have your own implementation of that button KeyButtonView.java, and in that class you have mediaPlayer as a member variable, so when you have two buttons, respectively you have two instances of KeyButtonView class and two instances of mediaPlayer. Why don't you use one instance of mediaPlayer, let's say you make it static, and make playSound() and initMediaPlayer() methods synchronized and static, this should be a quick and simple change, just to test if there is the issue. And something else, you use onTouch() to handle a click, why don't you try with OnClickListener? If you do not use onTouch properly you will end with bunch of calls on the UI thread, and each blocking at prepare(), this is not good. Once you fix this issue, you should consider rewrite it with prepareAsync() and setOnPreparedListener().
What i have:
I have implemented three MediaPlayer.Objects in my App.
All Three are created using a thread:
protected void onResume() {
// Threads
mTT1 = new TrackThread(this, R.raw.audiofile1, 1, mHandler);
mTT2 = new TrackThread(this, R.raw.audiofile2, 2, mHandler);
mTT3 = new TrackThread(this, R.raw.audiofile3, 3, mHandler);
// start thread
mTT1.start();
mTT2.start();
mTT3.start();
super.onResume();
}
"simplified" Code in the Thread for creating:
public class TrackThread extends Thread implements OnPreparedListener {
...
...
...
public void run() {
super.run();
try {
mMp.setDataSource(afd.getFileDescriptor(),
afd.getStartOffset(), afd.getDeclaredLength());
mMp.prepare();
} catch (IllegalArgumentException | IllegalStateException
| IOException e) {
Log.e(TAG, "Unable to play audio queue do to exception: "
+ e.getMessage(), e);
}
}
As I read in several Tutorials the "prepare()" methode takes a little bit of time to finish. Therefore i implemented a "Waiting loop" which waits until all MPs are prepared and created.
When "prepare and create" are done i enable the Start button and i want to start all 3 Mediaplayers SIMULTANEOUSLY.
I again use a Thread for dooing so:
public void onClick(View v) {
// Button 1
if (mBtn.getId() == v.getId()) {
mTT1.startMusic();
mTT2.startMusic();
mTT3.startMusic();
}
Code in the thread:
public class TrackThread extends Thread implements OnPreparedListener {
...
...
...
// start
public void startMusic() {
if (mMp == null)
return;
mMp.start();
}
Please note that the code above is not the full code, but it should be enough to define my problem.
What i want, My problem:
All MPs should play their Music in Sync, unfortunately sometimes when i start the music, there is a time delay between them.
The MPs must start at the exact same time as the 3Audio-files must be played simultaneously (and exactly in sync)
What i have already tried:
+) using SoundPool: My Audio-files are to big(5Megabyte and larger) for SoundPool
+) seekTo(msec): i wanted to seek every MP to a Specific time: eg.: 0, but this did not solve the problem.
+) to reach more Programmers i also asked this question on: coderanch.com
I hope somebody can help me!
Thanks in advance
The bottleneck here will certainly be preparing the mediaplayers to play. The Android framework provides an asynchronous method to perform this loading, and so with a bit of synchronization code you should be able to get these audio sources to play at roughly the same time. To keep from sound artifacting, you'll want less than 10ms of latency.
Initialize an atomic counter, C, to the number of things to load.
Use the prepareAsync() functions within MediaPlayer to prepare all three. Immediately after calling prepareAsync, supply a listener using setOnPreparedListener(listener).
Inside this listener, decrement C and check the value. If the value is greater than 0, wait on an object using the java object .wait() function. If the value is equal to 0, call notifyAll() on the object to wake up all of the other mediaplayer prepared-listener callback threads.
public void startMediaPlayers(List<MediaPlayer> mediaPlayers) {
private AtomicInteger counter = new AtomicInteger(mediaPlayers.size());
Object barrier = new Object();
/* start off all media players */
for (MediaPlayer player : mediaPlayers) {
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(final MediaPlayer mediaPlayer) {
int value = counter.decrementAndGet();
if (value == 0) {
// all media players are done loading.
// wake up all the ones that are asleep
barrier.notifyAll();
} else {
while (value > 0) {
try {
// wait for everyone else to load
barrier.wait();
} catch (InterruptedException e) {
// ignore
}
}
}
mediaPlayer.start();
callback.success(true);
}
player.prepareAsync();
}
}
As nobody could help me I found a solution on my own. MediaPlayer did not fulfill my requirements but Android JETPlayer in combination with JETCreator did.
CAUTION: Installing Python for using JETCreator is very tricky, therfore
follow this tutorial. And be careful with the versions of python and wxpython, not all versions support the JETCreator.
I used:
Python Version 2.5.4 (python-2.5.4.msi)
wxPython 2.8 (wxPython2.8-win32-unicode-2.8.7.1-py25.exe)
For those who do not know how to implement the Jetplayer watch this video
(at min.5 he starts with programming the Jetplayer).
Unfortunately I do not speak French so I just followed the code which worked for me.
Using Android JETCreator you can create your own JET Files and use them as your resource.
Useful links:
Demo data
Manual
Code/class
I'm developing a new app and am using VideoView to display mpeg clips.
I need to switch between videos very quickly, however, loading a new clip to a VideoView seems to take about half a second of black screen.
The transition must be seamless, how would you go about solving this kind of problem?
I had a similar issue and resolved with a still-image (ImageView) transition:
build a FrameLayout with an ImageView over the VideoView
the ImageView shows the first frame of the video
initially the ImageView is visible
start the video, wait for an arbitrary time (e.g. 2-300ms)
hide the ImageView
to switch two videos:
- show the image
- switch the video
- hide the image
a bit hackish but worked for me
I faced the same problem, but I used mediaplayer, my code is:
Here I use a button to trigger the switch action, before switching, I have already loaded the video and prepare for switching. When you need to do so, you just need to stop and release the old mediaplayer and starting the new one.The key point for seamless switching is the sleep(), when the process is sleeping, actually the video is still going on, but give the system some time to prepare for the next one.
switch_button = (Button) findViewById(R.id.button_switch);
switch_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Button switch_button = (Button) v;
VideoPlayer2 = new MediaPlayer();
try {
VideoPlayer2.setDataSource("rtsp://" + hostIP + ":1935/vod/Timer.mp4");
VideoPlayer2.prepare();
VideoPlayer2.setAudioStreamType(AudioManager.STREAM_MUSIC);
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
VideoPlayer.release();
VideoPlayer2.setDisplay(vidHolder);
VideoPlayer2.start();
}
});
Hey,
I'm using MediaPlayer to play a regular ShoutCast stream. The code is straightforward with prepareAsync() and a handler to start the playback. While it works flawlessly with some streams like DI.FM or ETN.FM (http://u10.di.fm:80/di_progressive), with others (http://mp3.wpsu.org:8000/) it won't go past the prepare state. No other listeners are called either.
//Uri streamUri = Uri.parse("http://u10.di.fm:80/di_progressive"); /* works */
Uri streamUri = Uri.parse("http://mp3.wpsu.org:8000/"); /* stuck on prepare state */
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(this.getBaseContext(), streamUri);
mediaPlayer.prepareAsync();
Any feedback is appreciated!
I think that there are some compatibility problems with the server end.
This is rather strange since the emulator handles it ok in my case - just not on my Froyo Galaxy S, even though it is the same API version.
It could be a codec issue, http streaming issue, I do not know.
But all the servers that fail tend to be old ones, with "Copyright 1998 - 2004" at the bottom... Not exactly recent or up to date you would think.
One potential workaround (which I have not tried yet) would be to use the StreamProxy, which would also make your code compatible with 2.1 and possibly earlier versions too. At the cost of extra work, extra code, and without doubt extra bugs...
In case you are not aware of it, there is another player bug report for 2.2 which may be relevant too:
Basic streaming audio works in 2.1 but not in 2.2
I'm facing an issue when MP "hangs" at preparing state too long (stream) and i'm trying to stop it using reset(). This causes MP to hang and thus my whole app freezes. Seems like there is no way to stop MP at preparing state. Im thinking on use prepare() wrapped in thread instead of prepareAsync(). Then i'll be able to kill that thread. As for now i did it in following way:
private void actionCancel(){
try {
mp.setDataSource(new String());
} catch (Exception e) {
e.printStackTrace();
android.util.Log.d(TAG,"actionCancel(): mp.setDataSource() exception");
mp.reset();
}
}
and it works 4me.
Additionally i have a following counter:
#Override
public void onBufferingUpdate(final MediaPlayer mp, final int percent) {
if (!mp.isPlaying()){
// android.util.Log.d(TAG,"onBufferingUpdate(): onBufferingUpdateCount = "+onBufferingUpdateCount);
if (onBufferingUpdateCount>MAX_BUFFERING_UPDATES_AT_PREPARING_STATE)
restartMP();
onBufferingUpdateCount++;
return;
}
}
i'd discover this listener always triggers at preparing state. So if it triggers more than 10 times and MP is still not playing i'm just restarting it:
private void restartMP(){
if (mp!=null)
if (mpState==MediaPlayerState.Preparing)
actionCancel();
else
mp.reset();
else
mp = new MediaPlayer();
mpState = MediaPlayerState.Idle;
onBufferingUpdateCount=0;
//isRequestCancelled=false;
requestTrackInfoStartedAt=0;
requestPlay();
}
note MediaPlayerState is my custom enum which has "Preparing" value. Also mpState is a class property/field which holds current MediaPlayerState state. Before starting prepareAsync() im setting mpState to MediaPlayerState.Preparing after it completes im setting it to MediaPlayerState.Started or other corresponding value.