My ProgressDialog will not show up. In my program the user selects bitrate from a pop up menu, the content is fetched online and displayed in VideoView.
However, all I get is a black screen while the video loads and the progressDialog is display for a split second (or less) at end before the video finally loads.
private void showPopupMenu(View v){
popupMenu = new PopupMenu(VideoPlayer.this, v);
if(bitRates != null){
int menuItem = 0;
int index = bitRates.size()-1;
popupMenu.getMenu().add(0,menuItem, 0,"Hide menu");
for(int i=1;i<bitRates.size();i++){
menuItem = i;
popupMenu.getMenu().add(0,menuItem, 0,"Quality"+" : "+bitrateCheck(bitRates.get(index))).setCheckable(true);
Log.i("ITEM",qualityList.get(i)+" : "+bitRates.get(i));
index--;
}
popupMenu.getMenu().add(0,menuItem++, 0,"Catalog");
}
popupMenu.show();
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(final MenuItem item) {
p_dialog = ProgressDialog.show(VideoPlayer.this, "", "Loading...");
//get current position of video to seek to
final int position = mVideoView.getCurrentPosition();
new Thread() {
public void run() {
try{
runOnUiThread(new Runnable() {
public void run() {
if(item.getTitle().equals("Catalog")){
backButtonVideo(new View(VideoPlayer.this));
}
else if(item.getTitle().equals("Hide menu")){
popupMenu.dismiss();
mVideoView.start();
}
else{
play(streamUrls.get(item.getItemId()),position);
}
}
});
}
catch (Exception e) {
Log.e("tag", e.getMessage());
}
p_dialog.dismiss();
}
}.start();
return true;
}
});
}
public void play(String _videoUri, int position){
Log.i(TAG,"URI is : "+Uri.parse(_videoUri).toString());
//View view = new View()
MediaController mc = new MediaController(VideoPlayer.this);
mVideoView.setMediaController(mc);
mVideoView.setVideoURI(Uri.parse(_videoUri));
mVideoView.requestFocus();
mVideoView.seekTo(position);
mVideoView.start();
}
////////////////////////Edit with new Code: as per suggestions/////////////////////
Now the dialog does not show at all.
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
mVideoView.start();
}
});
///////////////////////////////////////////////////////////////////////////////////
popupMenu.show();
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(final MenuItem item) {
//get current position of video to seek to
final int position = mVideoView.getCurrentPosition();
p_dialog = ProgressDialog.show(VideoPlayer.this, "", "Loading...");
try{
if(item.getTitle().equals("Catalog")){
backButtonVideo(new View(VideoPlayer.this));
}
else if(item.getTitle().equals("Hide menu")){
popupMenu.dismiss();
mVideoView.start();
}
else{
play(streamUrls.get(item.getItemId()),position);
}
}
catch (Exception e) {Log.e("tag", e.getMessage());}
return true;
}
});
}
public void play(String _videoUri, int position){
Log.i(TAG,"URI is : "+Uri.parse(_videoUri).toString());
MediaController mc = new MediaController(VideoPlayer.this);
mVideoView.setMediaController(mc);
mVideoView.setVideoURI(Uri.parse(_videoUri));
mVideoView.requestFocus();
mVideoView.seekTo(position);
p_dialog.dismiss();
}
Firstly, it makes no sense to create a separate thread only to run something back on the UI thread (why do you create the thread in the first place then?).
onMenuItemClick should already be called by the UI thread (callbacks for UI elements generally do this).
What you should look at is using a MediaPlayer.OnPreparedListener with VideoView.setOnPreparedListener. This will give you an indication of when the video is ready to be played.
I did some rearrangement as per Che Jami and got it to work. Thanks
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
p_dialog.dismiss();
mVideoView.start();
}
});
////////////////////////////////////////////////////////////////////////////////
popupMenu.show();
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(final MenuItem item) {
//get current position of video to seek to
final int position = mVideoView.getCurrentPosition();
try{
if(item.getTitle().equals("Catalog")){
backButtonVideo(new View(VideoPlayer.this));
}
else if(item.getTitle().equals("Hide menu")){
popupMenu.dismiss();
mVideoView.start();
}
else{
p_dialog = ProgressDialog.show(VideoPlayer.this, "", "Loading new stream");
play(streamUrls.get(item.getItemId()),position);
}
}
catch (Exception e) {Log.e("tag", e.getMessage());}
return true;
}
});
}
public void play(String _videoUri, int position){
Log.i(TAG,"URI is : "+Uri.parse(_videoUri).toString());
MediaController mc = new MediaController(VideoPlayer.this);
mVideoView.setMediaController(mc);
mVideoView.setVideoURI(Uri.parse(_videoUri));
mVideoView.requestFocus();
mVideoView.seekTo(position);
}
I have the same problem...i've tried you solution but my progress gets blocked...everything stops...and video doesn't show up...it seems that onPrepareListener is never called up...any ideas? Also it seems that setVideoURI has never passed in code...:/
I have different versions of code...with threads, with runOnUI, with AsyncTask, without everything...nothing seems to be working fully. something is always missing.
EDIT:
I have function that I'm calling in onClickListener
Here is a code like yours without any threads:
Version 1: Video starts after few seconds, progress dialog just show for a moment when video starts. Progress isn't showed from the beginning.
public void loadService(final int mode) {
//Version 1
// Show dialog
loadService = new ProgressDialog(activity);
loadService.setTitle("Loading service");
loadService.setMessage("Please wait...");
loadService.setCancelable(false);
loadService.show();
// Hide progress dialog after 15 seconds if nothing happens
DuoTVGuiHandler.progressBarProttection(loadService, 15);
// Setup video view for playback
if (mode == STAND_ALONE) {
setupVideoView(((DuoTVGuiActivity) activity).getVideoPlayback());
}
if (mode == WIDGET_MODE) {
setupVideoView(((MainActivity) activity).getVideoViewWidgetMode());
}
}
/** Setup video view for playback */
public void setupVideoView(final VideoView videoView) {
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
loadService.dismiss();
videoView.start();
}
});
videoView.setVideoURI(Uri.parse(channels.get(index).getFilePath()));
}
Version 2 with thread and handler...progress dialog is showed...its spinning...video shows for a second...and the app crashes...WrongThread for UI exception...but when i move setVideoURI in runOnUiThread...progress just stays forever...and setOnVideoURI is never finished.
public void loadService(final int mode) {
// //////////////////////////////
// Version 2
// //////////////////////////////
// Show dialog
loadService = new ProgressDialog(activity);
loadService.setTitle("Loading service");
loadService.setMessage("Please wait...");
loadService.setCancelable(false);
loadService.show();
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
loadService.dismiss();
super.handleMessage(msg);
}
};
Thread loadVideoPath = new Thread(new Runnable() {
public void run() {
if (mode == STAND_ALONE) {
((DuoTVGuiActivity) activity)
.getVideoPlayback()
.setVideoURI(
Uri.parse(channels.get(index).getFilePath()));
}
if (mode == WIDGET_MODE) {
((MainActivity) activity)
.getVideoViewWidgetMode()
.setVideoURI(
Uri.parse(channels.get(index).getFilePath()));
}
handler.sendEmptyMessage(0);
}
});
loadVideoPath.start();
}
Hope you have some idea...I've lost few days on this...and cant see solution...for this pretty basic thing...it drives me crazy :)
Related
I am Playing a Audio from Uri Its Working Fine.
Clicking a Button from Each Listview item.
Problem :Audio is Playing in the Listview ,but still Seekbar is not Moving(Updating).
EDIT:1
1.Audio is Playing in the Each Listview Item Perfectly,But Seekbar is Not Working(Not Updating).
Please Help me top solve this Issue.
My Listview Array adapter Class:
Adapter.class
private static final int UPDATE_FREQUENCY = 500;
int progress=0;
public View getView(final int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView = inflater.inflate(R.layout.audio_listview, null, true);
ListenAUdioButton = (Button) rowView.findViewById(R.id.ListenAudiobuttonxml);
seek_bar_view = (SeekBar) rowView.findViewById(R.id.seek_bar);
ListenAUdioButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// text_shown.setText("Playing...");
try {
try {
// get Internet status
isInternetPresent = cd1.isConnectingToInternet();
// check for Internet status
if (isInternetPresent) {
if (!itemname3_AUDIO_FILE[position].equals("") || !itemname3_AUDIO_FILE[position].equals("null")) {
System.out.println(" AUDIO FILE :-)" + itemname3_AUDIO_FILE[position]);
player = new MediaPlayer();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource(context, Uri.parse(itemname3_AUDIO_FILE[position]));
player.prepareAsync();
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
try {
mp.start();
seek_bar_view.setMax(player.getDuration());
updatePosition();
} catch (Exception e) {
e.printStackTrace();
}
}
});
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
stopPlay();
}
});
MediaPlayer.OnErrorListener onError = new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// returning false will call the OnCompletionListener
return false;
}
};
} else {
Toast.makeText(getContext(), "Audio Not Found..!", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getContext(), "Please Check Your Internet Connection..!", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), "Audio Not Found..!", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
return rowView;
}
private void stopPlay() {
player.stop();
player.reset();
// playButton.setImageResource(android.R.drawable.ic_media_play);
handler.removeCallbacks(updatePositionRunnable);
seek_bar_view.setProgress(0);
// isStarted = false;
}
private final Handler handler = new Handler();
private final Runnable updatePositionRunnable = new Runnable() {
public void run() {
updatePosition();
}
};
private void updatePosition()
{
handler.removeCallbacks(updatePositionRunnable);
seek_bar_view.setProgress(progress);
progress=getProgressPercentage(player.getCurrentPosition(),player.getDuration();
notifyDataSetChanged();
handler.postDelayed(updatePositionRunnable, UPDATE_FREQUENCY);
}
you need to update your seekbar position(value) at every second..
To set seekbar Max value..
seek_bar_view.setMax((int) player.getDuration());
and update it every second to show progress
Handler mHandler = new Handler();
runOnUiThread(new Runnable() {
#Override
public void run() {
seek_bar_view.setProgress((int) player.getCurrentPosition());
}
mHandler.postDelayed(this,1000);
}
);
See this:
seek_bar_view.setProgress(player.getCurrentPosition());
here player.getCurrentPosition() returns the time in millis , you need to convert this to int and then set the progress to seekBar.
Try this:
public static int getProgressPercentage(long currentDuration, long totalDuration){
Double percentage = (double) 0;
long currentSeconds = (int) (currentDuration / 1000);
long totalSeconds = (int) (totalDuration / 1000);
// calculating percentage
percentage =(((double)currentSeconds)/totalSeconds)*100;
// return percentage
return percentage.intValue();
}
and now get the percentage for your SeekBar like this:
int currentProgress=getProgressPercentage(player.getCurrentPosition(), player.getDuration());
seek_bar_view.setProgress(currentProgress);
Edited:
For your specific case, inside a ListView item:
You will need to notify the adapter each time you change the position of seekbar.
For this, the simplest approach would be to take a variable inside the POJO class you are using to set the adapter.
Inside your POJO class
int progress=0;
In your adapter,set the seekbar progress
seekbar.setProgress(progress);
In your adapter,change the value of progress and notifyadapter
progress=getProgressPercentage(player.getCurrentPosition(), player.getDuration());
notifyDataSetChanged()
//Re-Edited:
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {
// TODO Auto-generated method stub
notifyDataSetChanged();
}
});
Native Android Media player does not invoke onCompletion method after the video has ran it's duration.
I have an Activity that plays a single video or a list of videos (m3u8 file). Video plays file as it should, I can use the media controller as well, however, when the video runs out, after a few seconds he starts a loop. onCompletion method doesn't activate unless the user clicks (or double taps) the fast forward option on media controler.
Is there a way to make the onComplete method activate automatically when the video runs out? (I've tried using the listener, doesn't work). Pointing out what I did wrong also works.
Here is the activity that handles video playing:
public class VideoActivity extends ActionBarActivity implements MediaPlayer.OnCompletionListener {
private static final String TAG = VideoActivity.class.getSimpleName();
private VideoView mVideoViewStream1;
ProgressDialog mDialog;
private String mURL;
private ChannelPlaylist mChannelPlaylist;
private int mIndex;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
// Validate internet connection
if (!Util.isDeviceConnected(this)) {
FragmentManager fm = getSupportFragmentManager();
PopUpErrorFragment popupError = PopUpErrorFragment.newInstance(getString(R.string.errorInternetConnection));
popupError.show(fm, PopUpErrorFragment.TAG);
finish();
}
// Assign controls to their variable representations
mVideoViewStream1 = (VideoView) findViewById(R.id.vvVideo);
// Retrieve bundle data
Intent i = getIntent();
Bundle bundle = i.getExtras();
ChannelPlaylist channelPlaylist = bundle.getParcelable(KeyHelper.BUNDLE_CHANNEL_PLAYLIST);
if (channelPlaylist != null) {
this.mChannelPlaylist = channelPlaylist;
if (bundle.containsKey("index") && mIndex == 0) {
this.mIndex = bundle.getInt("index");
} else {
if (this.mIndex == 0) {
this.mIndex = this.mChannelPlaylist.getIndex();
}
}
this.mURL = this.mChannelPlaylist.getSchedule().get(mIndex).getStream_url();
} else {
this.mURL = bundle.getString("url");
}
progressDialog();
standardAndroidPlayer();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.video, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/***************************** CLASS METHODS **************************************************/
/**
* Dismissess the dialog
*/
private void dismissDialog() {
if (this.mDialog != null) {
mDialog.dismiss();
}
}
/**
* Standard android player
*/
private void standardAndroidPlayer() {
try {
// Start the MediaController
MediaController mediacontroller = new MediaController(this);
mediacontroller.setAnchorView(mVideoViewStream1);
// Get the URL from String VideoURL
mVideoViewStream1.setMediaController(mediacontroller);
// Set media player completion listener
mVideoViewStream1.setOnCompletionListener(this);
mVideoViewStream1.setVideoURI(Uri.parse(this.mURL));
mVideoViewStream1.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
//Log.i(TAG, "Duration = " + mVideoViewStream1.getDuration());
if (mp.isLooping()) mp.setLooping(false);
}
});
mVideoViewStream1.requestFocus();
mVideoViewStream1.start();
} catch (Exception e) {
dismissDialog();
Log.e(TAG, "Error" + e.getMessage());
e.printStackTrace();
}
dismissDialog();
}
#Override
public void onCompletion(MediaPlayer mp) {
this.mIndex++;
if (this.mIndex < mChannelPlaylist.getSchedule().size()) {
this.mURL = this.mChannelPlaylist.getSchedule().get(this.mIndex).getStream_url();
standardAndroidPlayer();
} else {
finish();
}
}
/**
* Creates a progress dialog
*/
private void progressDialog() {
// Create a progressbar
mDialog = new ProgressDialog(VideoActivity.this);
// Set progressbar title
mDialog.setTitle("Android Video Streaming Tutorial");
// Set progressbar message
mDialog.setMessage("Buffering...");
mDialog.setIndeterminate(false);
mDialog.setCancelable(false);
// Show progressbar
mDialog.show();
}
}
Edited:
Ok, for some strange reason, on mobile phone the method doesn't fire off, however when used on tablet, it does. I wasn't able to reproduce the effect on tablet and didn't have any success on the phone either. Does it have something to do with the versions of android? Since I didn't get any warnings about compatibility when writing the listener, I didn't think much about it.
Try this.
mVideoViewStream1.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
finish();
}
});
I have asked this question 2 times now still haven't got it to work. Any help would be awesome
My ProgressBar does not reset after audio is done, the bar just stays to the max blue line. I ask a question before on this and got it working but now just stopped working and not sure why it doesn't. Any help would be awesome.
All I want is it to chose a audio at random then play one and when finished you can press play again to listen to the same audio it chose at random.
Heres code:
public class player2 extends Activity implements Runnable {
private MediaPlayer mp;
private ProgressBar progressBar;
private ImageButton pauseicon;
private final int NUM_SOUND_FILES = 3; //*****REPLACE THIS WITH THE ACTUAL NUMBER OF SOUND FILES YOU HAVE*****
private int mfile[] = new int[NUM_SOUND_FILES];
private Random rnd = new Random();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.player_2);
pauseicon = (ImageButton) findViewById(R.id.pauseicon);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
getActionBar().setDisplayHomeAsUpEnabled(true);
mfile[0] = R.raw.sound04; //****REPLACE THESE WITH THE PROPER NAMES OF YOUR SOUND FILES
mfile[1] = R.raw.sound05; //PLACE THE SOUND FILES IN THE /res/raw/ FOLDER IN YOUR PROJECT*****
mfile[2] = R.raw.sound06;
// Listeners
/**
* Play button click event
* plays a song and changes button to pause image
* pauses a song and changes button to play image
* */
try{
mp = MediaPlayer.create(player2.this, mfile[rnd.nextInt(NUM_SOUND_FILES)]);
mp.seekTo(0);
mp.start(); ;
progressBar.setVisibility(ProgressBar.VISIBLE);
progressBar.setProgress(0);
progressBar.setMax(100);
new Thread(this).start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
mp.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
pauseicon.setImageResource(R.drawable.playicon);
}
});
pauseicon.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
// No need to check if it is pauseicon
if(mp.isPlaying()){
mp.pause();
((ImageButton) v).setImageResource(R.drawable.playicon);
} else {
mp.start();
((ImageButton) v).setImageResource(R.drawable.pauseicon);
}}});
}
public void run() {
int currentPosition= 0;
int total = mp.getDuration();
while (mp!=null && currentPosition<=total) {
try {
Thread.sleep(1000);
currentPosition= mp.getCurrentPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
progressBar.setProgress(currentPosition);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
if (mp != null)
if(mp.isPlaying())
mp.stop();
mp.release();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onBackPressed(){
if (mp != null){
if(mp.isPlaying())
mp.stop();
mp.release();
}
//there is no reason to call super.finish(); here
//call super.onBackPressed(); and it will finish that activity for you
super.onBackPressed();
}
}
I did not check all the code thoroughly, but at a quick glance I would guess that your thread (which updates the progress bar) is stopping at completion and you never start it again (ie. when the user clicks play again). Just try restarting the thread in your pauseicon.setOnClickListener (when playback is complete). Example:
pauseicon.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(mp.isPlaying()) {
mp.pause();
((ImageButton) v).setImageResource(R.drawable.playicon);
} else {
mp.start();
((ImageButton) v).setImageResource(R.drawable.pauseicon);
// RESTART THE UPDATE THREAD //
new Thread(this).start();
}
}
});
EDIT using a static variable to store thread so that it can be restarted from the view's onClick method:
// add this to your class as a member
static Thread progressThread = new Thread(this);
// add this to BOTH onCreate and onClick
progressThread.start();
If this does not work (I can't test it out right now), you can simply keep the thread running, for example:
// flag to set when thread should be actively running
static boolean runThread = true;
// change your run method to something as follows
public void run() {
while ( runThread ) {
if ( mp != null && currentPosition <= total ) {
int currentPosition= 0;
int total = mp.getDuration();
try {
Thread.sleep(1000);
currentPosition= mp.getCurrentPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
progressBar.setProgress(currentPosition);
}
else
Thread.sleep(1000);
}
}
// then when you no longer need to update the progress bar set the flag to false,
// which will cause your thread to finish. this can go anywhere, depending on
// your needs
runThread = false;
I am attempting to display a ProgressDialog while I am loading a video.
My play(String _videoUri) function doesn't seem to get called.
Can anyone tell me why?
I have this exact same setup for starting a new Intent and it seems to work fine, but not in this case or loading a video from a given URL.
private void showPopupMenu(View v){
PopupMenu popupMenu = new PopupMenu(VideoPlayer.this, v);
if(bitRates != null){
for(int i=0;i<bitRates.size();i++){
int menuItem = i;
popupMenu.getMenu().add(0,menuItem, 0,"BitRate: "+bitRates.get(i));
}
}
popupMenu.show();
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(final MenuItem item) {
progressDialog = ProgressDialog.show(VideoPlayer.this, "", "Loading video...");
new Thread() {
public void run() {
try{
play(streamUrls.get(item.getItemId()));
}
catch (Exception e)
{
Log.e("tag", e.getMessage());
}
progressDialog.dismiss();
}
}.start();
return true;
}
});
}
public void play(String _videoUri){
Log.i(TAG,"URI is : "+Uri.parse(_videoUri).toString());
MediaController mc = new MediaController(VideoPlayer.this);
mVideoView.setMediaController(mc);
mVideoView.setVideoURI(Uri.parse(_videoUri));
mVideoView.requestFocus();
mVideoView.start();
}
Try putting your anonymous thread in parentheses.
(new Thread() { ... }).start()
Does anyone know if it's possible to detect when a VideoView is buffering?
I want to show a ProgressDialog when the video is buffering.
So far I tried using a OnPreparedListener, but that only works when the video is first loaded. If a video is playing and the user moves the scrub bar to a different point the video is still "prepared" even though it is buffering.
I also tried (I know this is awful) an AsyncThread that just busy waits on isPlaying():
private class BufferTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void...voids) {
final VideoView videoView = (VideoView)findViewById(R.id.video);
while (!videoView.isPlaying()) { }
return null;
}
protected void onPostExecute(Void v) {
// Hide the dialog here...
}
}
This doesn't work because as soon as you call start() a VideoView seems to be considered playing even though it is buffering.
The only solution I can think of is building a custom VideoView type class so I can access its MediaPlayer instance.
Any ideas? Thanks for reading.
Since API level 17, you can now access the InfoListener from the MediaPlayer:
final MediaPlayer.OnInfoListener onInfoToPlayStateListener = new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
switch (what) {
case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: {
mProgressBar.setVisibility(View.GONE);
return true;
}
case MediaPlayer.MEDIA_INFO_BUFFERING_START: {
mProgressBar.setVisibility(View.VISIBLE);
return true;
}
case MediaPlayer.MEDIA_INFO_BUFFERING_END: {
mProgressBar.setVisibility(View.GONE);
return true;
}
}
return false;
}
});
mVideoView.setOnInfoListener(onInfoToPlayStateListener);
I came with the following hack in order to not implement a custom VideoView. The idea is to check every 1 second if the current position is the same as 1 second before. If it is, the video is buffering. If not, the video is really playing.
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
int duration = videoView.getCurrentPosition();
if (old_duration == duration && videoView.isPlaying()) {
videoMessage.setVisibility(View.VISIBLE);
} else {
videoMessage.setVisibility(View.GONE);
}
old_duration = duration;
handler.postDelayed(runnable, 1000);
}
};
handler.postDelayed(runnable, 0);
videoMessage is just a TextView with the text "Buffering..." placed in the center of my VideoView.
Following code will show a buffering dialog every time the VideoView is buffering.
final ProgressDialog bufferingDialog;
bufferingDialog = ProgressDialog.show(context,
"Buffering", "Please wait", true, true);
VideoView videoView;
videoView = (VideoView) findViewById(R.id.video_view);
videoView.setVideoPath(path);
videoView.setMediaController(new MediaController(context));
videoView.requestFocus();
videoView.start();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START)
bufferingDialog.show();
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END)
bufferingDialog.dismiss();
return false;
}
});
}
});
videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
bufferingDialog.dismiss();
return false;
}
});
VideoView showing Progress while Buffering.
Below code worked for me:
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(final MediaPlayer mp) {
mp.start();
mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
switch (what) {
case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: {
progressBar.setVisibility(View.GONE);
return true;
}
case MediaPlayer.MEDIA_INFO_BUFFERING_START: {
progressBar.setVisibility(View.VISIBLE);
return true;
}
case MediaPlayer.MEDIA_INFO_BUFFERING_END: {
progressBar.setVisibility(View.GONE);
return true;
}
}
return false;
}
});
}
});
I'm working on something similar, and couldn't come up with a great solution. Some interesting solutions were posted here that you should check out if you haven't seen them.
Anyway, I came up with the following hack that was hinted at in the above thread and works ok for now.
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
float temp = ((float)mp.getCurrentPosition() / (float)mp.getDuration())*100;
if(Math.abs(percent - temp) < 1) {
buffer_fail++;
if(buffer_fail == 15) {
//buffer failed
}
}
}
This worked for me
boolean b_start = true;
boolean b_end = true;
final MediaPlayer.OnInfoListener onInfoToPlayStateListener = new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
switch (what) {
case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: {
dialog1.setVisibility(View.GONE);
b_end = false;
b_start = false;
}
case MediaPlayer.MEDIA_INFO_BUFFERING_START: {
if (b_start){
dialog1.setVisibility(View.VISIBLE);
}
b_start = true;
}
case MediaPlayer.MEDIA_INFO_BUFFERING_END: {
if(b_end){
dialog1.setVisibility(View.VISIBLE);
}
b_end = true;
}
}
return false;
}
};
videoView.setOnInfoListener(onInfoToPlayStateListener);