How to create streaming video player for large content?
Asked Answered
P

1

7

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);
}
Personalize answered 29/8, 2011 at 12:56 Comment(7)
Without telling us what you've done so far and posting the code you are currently using it is VERY unlikely that anyone here will be able to solve that problem.Eighth
SO is a site to ask specific programming questions.Rubyeruch
I know that SO is specifically for programming question i am not asking for specific code but core logic for creating such a streaming player then too i am adding my code used for creating my playerPersonalize
If you use VideoView, and get lags, then you've reached limits of device's hardware. There's probably little that you could improve on your side.Fylfot
How does it respond in the emulator?Michellemichels
Emulator shows some weird result some times the video plays and sometimes it doesn't.Personalize
Could you share the layout for this code? I think the whole code would be a nice reusable component for many apps. Thanks!Idiomatic
H
2

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.

Humpage answered 12/2, 2012 at 14:17 Comment(1)
We manage to play video nicely by making encoding the videos properly. Thanks for your reply.. :-)Personalize

© 2022 - 2024 — McMap. All rights reserved.