'How to play/prepare a video in the background during displaying another video?
I want to play/prepare a video in the background during displaying another video. To prevent black loading before video start. First I describe my code and then the problem.
I use a RelativeLayout as container. Which has an event and hides the added view in the onChildViewAdded method.
RelativeLayout containerRelativeLayout = activity.findViewById(R.id.containerRelativeLayoutLayout);
containerRelativeLayout.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override
public void onChildViewAdded(View view, View view1) {
view1.setVisibility(View.INVISIBLE);
}
@Override
public void onChildViewRemoved(View view, View view1) {
}
});
A layout is created in a loop and built using addMediaToView. The layout is then added to the container view in the UI thread. The main thread waits until the surfaceCreated event releases the semaphore. In the next step the layout is set to visible when the video is loaded or the surface is created (surfaceCreated event).
while(true) //Main-Thread
{
RelativeLayout layout = new RelativeLayout(this.activity);
addMediaToView(layout, screen, media);
semaphore.acquire();
activity.runOnUiThread(()->{
containerRelativeLayout.addView(layout);
});
waitForSemaphore(semaphore); //surfaceCreated event releases the semaphore
semaphore.acquire();
activity.runOnUiThread(()->{
layout.setVisibility(View.VISIBLE);
semaphore.release();
});
waitForSemaphore(semaphore);
Thread.sleep(screen.getDuration() * 1000);
...
}
In this method, a SurfaceView and MediaPlayer are created and the SurfaceView is added to the passing layout. When the surfaceCreate event is triggered, the surfaceHolder is added to the player.
private void addMediaToView(RelativeLayout layout, Screen screen, Media media) {
RelativeLayout.LayoutParams relativeLayoutParam = resizeScreenMedia(media,screen);
final String path = "...";
SurfaceView surfaceView = new SurfaceView(activity);
MediaPlayer mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(path);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mp -> {
mp.setLooping(true);
mp.start();
});
SurfaceHolder holder = surfaceView.getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
mediaPlayer.setDisplay(surfaceHolder);
semaphore.release();
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
mediaPlayer.release();
}
});
} catch (IOException e) {
e.printStackTrace();
}
surfaceView.setLayoutParams(relativeLayoutParam);
layout.addView(surfaceView);
}
This works very well. However, there is one problem. When a new layout is created in the second pass and the method mediaPlayer.setDisplay(surfaceHolder); is called, the current SurfaceView is changed and the new video is set before the new layout is set to visible. So the SurfaceView from the old pass of the loop is changed.
The content of the first SurfaceView should not be changed. It should continue to run in the background so that the new SurfaceView lies on top of the old one. I know it might not be performant but I delete the old SurfaceView after the new one is displayed.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|