I worked for hours in developing a proper streaming video player in android and quite successful in creating a player which can play small contents such as songs, Trailers etc very fine. But the player shows some unusual behavior for large content such as Movies and TV shows as it require a lot of streaming, the player starts lagging for such data. Can any one help me out to crack the solution for such a problem.
Thanks in Advance...
Here is the source:
public class player extends Activity implements OnErrorListener,
OnPreparedListener {
/** Called when the activity is first created. */
private static final int UPDATE_FREQUENCY = 500;
private static final int STEP_VALUE = 4000;
private static final int DIALOG_KEY = 0;
private TextView currentTime, duration;
private VideoView videoView;
private SeekBar seekbar = null;
private View mediacontroller;
private ProgressDialog progressDialog = null;
private ImageButton playButton = null;
private ImageButton prevButton = null;
private ImageButton nextButton = null;
private boolean isMoveingSeekBar = false;
private boolean isMediaCtrlShown = false;
private final Handler handler = new Handler();
private boolean isStarted = true;
private String currentFile = "singham_320b";
private boolean isCustomSeekButtonClick = false;
private boolean isPauseButtonClick = false;
private static boolean isMyDialogShowing = false;
private static int percentageBuffer = 0;
private int mpCurrentPosition;
int hh = 00, mm = 00, ss = 00, ms = 00;
int i = 0;
int previouPosition = 0;
private Runnable onEverySecond=new Runnable() {
public void run() {
if (videoView!=null) {
seekbar.setProgress(videoView.getCurrentPosition());
}
if (!isPauseButtonClick) {
mediacontroller.postDelayed(onEverySecond, 1000);
}
}
};
private final Runnable updatePositionRunnable = new Runnable()
{
public void run()
{
updatePosition();
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setUpMyDialog();
showMyDialog();
videoView = (VideoView) findViewById(R.id.videoview);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
seekbar = (SeekBar) findViewById(R.id.seekbar);
currentTime = (TextView) findViewById(R.id.currentTime);
playButton = (ImageButton) findViewById(R.id.play);
prevButton = (ImageButton) findViewById(R.id.prev);
nextButton = (ImageButton) findViewById(R.id.next);
duration = (TextView) findViewById(R.id.duration);
mediacontroller = findViewById(R.id.mediacontroller);
videoView.setOnErrorListener(this);
videoView.setOnPreparedListener(this);
videoView.setOnTouchListener(new View.OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
if (!isMediaCtrlShown)
{
mediacontroller.setVisibility(View.GONE);
isMediaCtrlShown = true;
}
else
{
mediacontroller.setVisibility(View.VISIBLE);
isMediaCtrlShown = false;
}
return false;
}
});
Uri video = Uri.parse("http://wpc.1B42.edgecastcdn.net/001B42/mobile/songs/pyaar_ka_punchnama/life_sahi_hai_320b.mp4");
videoView.setVideoURI(video);
seekbar.setOnSeekBarChangeListener(seekBarChanged);
playButton.setOnClickListener(onButtonClick);
nextButton.setOnClickListener(onButtonClick);
prevButton.setOnClickListener(onButtonClick);
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
return false;
}
public void calculateTime(int ms) {
ss = ms / 1000;
mm = ss / 60;
ss %= 60;
hh = mm / 60;
mm %= 60;
hh %= 24;
}
@Override
public void onPrepared(MediaPlayer mp)
{
dismissMyDialog();
videoView.start();
mediacontroller.setVisibility(View.VISIBLE);
isMediaCtrlShown = false;
seekbar.setProgress(0);
seekbar.setMax(videoView.getDuration());
ms = videoView.getDuration();
calculateTime(ms);
duration.setText("" + hh + ":" + mm + ":" + ss);
ms = videoView.getCurrentPosition();
calculateTime(ms);
currentTime.setText("" + hh + ":" + mm + ":" + ss);
playButton.setImageResource(android.R.drawable.ic_media_pause);
updatePosition();
isStarted = true;
mp.setOnBufferingUpdateListener(new OnBufferingUpdateListener()
{
// show updated information about the buffering progress
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent)
{
Log.d(this.getClass().getName(), "percent: " + percent);
percentageBuffer = percent;
secondarySeekBarProgressUpdater(percent);
// progress.setSecondaryProgress(percent);
if (i == 0)
{
i = i + 1;
previouPosition = mp.getCurrentPosition();
}
else if (i == 1)
{
if (mp.getCurrentPosition() == previouPosition)
{
if (!isPauseButtonClick)
{
showMyDialog();
if (percent == 100)
{
dismissMyDialog();
}
}
}
else
{
i = 0;
previouPosition = 0;
dismissMyDialog();
}
}
else if (isCustomSeekButtonClick)
{
isCustomSeekButtonClick = false;
if (mpCurrentPosition == mp.getCurrentPosition())
{
showMyDialog();
if (percent == 100)
{
dismissMyDialog();
}
}
else
{
dismissMyDialog();
}
}
}
});
mp.setOnSeekCompleteListener(new OnSeekCompleteListener()
{
public void onSeekComplete(MediaPlayer mp)
{
if (mp.isPlaying())
{
}
else
{
onStart();
onPause();
onStart();
}
}
});
}
private SeekBar.OnSeekBarChangeListener seekBarChanged = new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
isMoveingSeekBar = false;
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
isMoveingSeekBar = true;
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser)
{
Log.e("",""+progress+""+percentageBuffer);
if (fromUser)
{
isCustomSeekButtonClick = fromUser;
videoView.seekTo(progress);
mpCurrentPosition = progress;
Log.e("OnSeekBarChangeListener", "onProgressChanged");
}
if (isMoveingSeekBar)
{
videoView.seekTo(progress);
Log.i("OnSeekBarChangeListener", "onProgressChanged");
}
}
};
private View.OnClickListener onButtonClick = new View.OnClickListener() {
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.play:
{
if (videoView.isPlaying())
{
handler.removeCallbacks(updatePositionRunnable);
isPauseButtonClick = true;
videoView.pause();
playButton.setImageResource(android.R.drawable.ic_media_play);
}
else
{
if (isStarted)
{
videoView.start();
isPauseButtonClick = false;
playButton.setImageResource(android.R.drawable.ic_media_pause);
updatePosition();
}
else
{
startPlay(currentFile);
isPauseButtonClick = false;
videoView.start();
}
}
break;
}
case R.id.next:
{
int seekto = videoView.getCurrentPosition() + STEP_VALUE;
if (seekto > videoView.getDuration())
seekto = videoView.getDuration();
videoView.pause();
videoView.seekTo(seekto);
/*
* try { Thread.sleep(15000); } catch (InterruptedException e) {
* // TODO Auto-generated catch block e.printStackTrace(); }
*/
// player.pause();
videoView.start();
break;
}
case R.id.prev: {
int seekto = videoView.getCurrentPosition() - STEP_VALUE;
if (seekto < 0)
seekto = 0;
videoView.pause();
videoView.seekTo(seekto);
// player.pause();
videoView.start();
break;
}
}
}
};
private void updatePosition()
{
handler.removeCallbacks(updatePositionRunnable);
seekbar.setProgress(videoView.getCurrentPosition());
ms = videoView.getCurrentPosition();
calculateTime(ms);
currentTime.setText("" + hh + ":" + mm + ":" + ss);
handler.postDelayed(updatePositionRunnable, UPDATE_FREQUENCY);
}
private void startPlay(String file)
{
Log.i("Selected: ", file);
// selelctedFile.setText(file);
seekbar.setProgress(0);
videoView.stopPlayback();
videoView.start();
seekbar.setMax(videoView.getDuration());
playButton.setImageResource(android.R.drawable.ic_media_pause);
updatePosition();
isStarted = true;
}
void setUpMyDialog()
{
if (progressDialog == null)
{
progressDialog = (ProgressDialog) onCreateDialog(DIALOG_KEY);
progressDialog = new ProgressDialog(player.this);
progressDialog.setMessage("Loading...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
}
}
void showMyDialog()
{
Log.e("showMyDialog***", "****" + isMyDialogShowing);
if (!isMyDialogShowing)
{
isMyDialogShowing = true;
Log.e("showMyDialog: true***", "****" + isMyDialogShowing);
if (progressDialog != null && !progressDialog.isShowing())
{
Log.e("showMyDialog: true***", "****progressDialog" + progressDialog.isShowing());
progressDialog.show();
}
else if(progressDialog == null)
{
setUpMyDialog();
progressDialog.show();
}
}
}
void dismissMyDialog()
{
Log.e("dismissMyDialog***", "****");
if (progressDialog != null && progressDialog.isShowing())
{
progressDialog.dismiss();
progressDialog = null;
isMyDialogShowing = false;
}
}
void killMyDialog()
{
isMyDialogShowing = false;
}
private void secondarySeekBarProgressUpdater(int percent){
seekbar.setSecondaryProgress(percent);
}
My intuition on this says you might be overlooking something by concentrating on the player, especially since it works fine for smaller content. Have you thought about checking the streaming server? If the server isn't up to the task of streaming larger files then there is little the player can do about it. Furthermore you might be able to adjust the packet size from the server to help the player manage playback using smaller 'bites' (pardon the pun) of media at a time. Try using the free Apple Darwin streaming server. There is a version for Apache, Windows and others, and it's very configurable. Get yourself a set of files of various sizes and try to establish at what size playback starts to fail. That figure will give you a big clue as to where the problem lies, be it in the transmitted server packet size, the available memory in the Android environment, or elsewhere. Whatever the figure, try setting a smaller packet size from the server. This should give your player less work to do and hopefully improve playback.
You can obtain the Darwin server from many places online. Here is one such link. Wikipedia has some useful information and some links for this server too, find them here. Good luck with your research on this.
Frank.