Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple video players in viewpager in android

I want to play videos on different fragments in viewpager. I use multiple mediaplayers and surfaceviews for each fragment. When I swipe left or right, I want to pause and start videos as well. Swipe to next video has no problem at all but when i swipe to previous video(that is already playing) surfaceviews overlap. Meanwhile, I can play and pause videos without problem.

I tried almost all possible combinations of setZorderMedia and setZOrderonTop but I failed.

In short, the problem is that surfaceviews overlap in viewpager. Here are the problem related codes, layouts and a screenshot of the problem.

Layout of the activity that contains viewpager

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_tweet_activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".TweetActivity" >

<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager_tweet"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />   
</RelativeLayout>

Fragment layout.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<ImageView
    android:id="@+id/image_avatar"
    android:layout_width="80dip"
    android:layout_height="80dip" />

<TextView
    android:id="@+id/text_user"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/image_avatar"
    android:layout_marginLeft="18dp"
    android:layout_toRightOf="@+id/image_avatar"
    android:text="TextView"
    android:textSize="7pt" />

<TextView
    android:id="@+id/text_tweet"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/image_avatar"
    android:layout_below="@+id/image_avatar"
    android:text="TextView"
    android:textSize="7pt" />

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/video_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:gravity="center_horizontal|center_vertical"
    android:orientation="vertical"
    android:layout_below="@+id/text_tweet" >

    <FrameLayout
        android:id="@+id/videoSurfaceContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <SurfaceView
            android:id="@+id/videoSurface"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </FrameLayout>
</RelativeLayout>


</RelativeLayout>

Fragment.class

    private Context context=getActivity();
private View rootView;
private Typeface type;

private SurfaceView videoSurface; 
private MediaPlayer player; 
private VideoControllerView controller;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
    rootView = inflater.inflate(R.layout.fragment_tweet, container, false);
    context=getActivity();

    videoSurface = (SurfaceView) rootView.findViewById(R.id.videoSurface);      
    //videoSurface.setZOrderMediaOverlay(false);
    //videoSurface.setZOrderOnTop(true);
    SurfaceHolder videoHolder = videoSurface.getHolder(); 
    videoHolder.addCallback(this);

    player = new MediaPlayer(); 
    controller = new VideoControllerView(context);


    RelativeLayout videoView=(RelativeLayout) rootView.findViewById(R.id.video_container);

    videoView.setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View arg0, MotionEvent arg1) {
            controller.show(); 
            return false;
        }           
    });


    try {
        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
        player.setDataSource(context, Uri.parse("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"));
        player.setOnPreparedListener(this);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return rootView;
}

// Implement SurfaceHolder.Callback
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    player.setDisplay(holder);
    player.prepareAsync();
    isSurfaceCreated=true;

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    player.release();
}
// End SurfaceHolder.Callback

// Implement MediaPlayer.OnPreparedListener
@Override
public void onPrepared(MediaPlayer mp) {
    controller.setMediaPlayer(this);
    controller.setAnchorView((FrameLayout) rootView.findViewById(R.id.videoSurfaceContainer));
    //player.start();
}
// End MediaPlayer.OnPreparedListener

// Implement VideoMediaController.MediaPlayerControl
@Override
public boolean canPause() {
    return true;
}

@Override
public boolean canSeekBackward() {
    return true;
}

@Override
public boolean canSeekForward() {
    return true;
}

@Override
public int getBufferPercentage() {
    return 0;
}

@Override
public int getCurrentPosition() {
    return player.getCurrentPosition();
}

@Override
public int getDuration() {
    return player.getDuration();
}

@Override
public boolean isPlaying() {
    return player.isPlaying();
}

@Override
public void pause() {
    player.pause();
}

@Override
public void seekTo(int i) {
    player.seekTo(i);
}

@Override
public void start() {
    player.start();
}

@Override
public boolean isFullScreen() {
    return false;
}

@Override
public void toggleFullScreen() {
}
// End VideoMediaController.MediaPlayerControl

My VideoControllerView

My activity that contains viewpager (again the problem related part in onCreate method of the activity)

currentFragment=pager.getCurrentItem();
    pager.setOnPageChangeListener(new OnPageChangeListener(){

        @Override
        public void onPageScrollStateChanged(int state) {
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int index) {

            TweetFragment current=pagerAdapter.getItem(currentFragment);
            current.pause();

            TweetFragment selected=pagerAdapter.getItem(index);
            selected.start();

            currentFragment=index;
        }
    });

Swipe to next video has no problem; Image 1

Swipe back to a video that is paused before; Image 2

If there is anymore necessary information, please ask.

like image 248
yasin_alm Avatar asked Feb 12 '14 12:02

yasin_alm


1 Answers

I think your problem is that you are using a SurfaceView for your video.

Try using a TextureView instead.

From documentation:

Unlike SurfaceView, TextureView does not create a separate window but behaves as a regular View. This key difference allows a TextureView to be moved, transformed, animated, etc.

Edit

I don't know why the negative vote, a SurfaceView will create a new window to draw its content. (This is an independent window from the window of the activity, see here ).

Also note that the zOrder calls need to be called before the surface view's containing window is attached to the window manager so you cant rearrange the zOrder of your SurfaceViews after they are created and attached.

If you really want to use multiple SurfaceViews at the same time you could try calling setVisibility (int visibility) on your SurfaceView when you switch pages.

Make your videoSurface variable public and call current.setVisibility(View.GONE) after current.pause() and current.setVisibility(View.VISIBLE) after current.start() .

I'm not sure if that will work though..

Your best bet would be to either create/destroy the SurfaceViews each time you change a page, or try using a TextureView as I mentioned before.

like image 156
Evripidis Drakos Avatar answered Oct 20 '22 21:10

Evripidis Drakos