Android的SurfaceView:图像显示后视频 [英] Android SurfaceView: Show Video after Images
问题描述
我想在同一个SurfaceView一对夫妇的图像后播放视频。如果我显示图片视频之后,一切工作正常。但是如果我想的影像后播放视频时,SurfaceView保持空白(黑色)。任何人都可以帮忙吗?这似乎是清除或重置SurfaceView的问题!
在SurfaceView的code(自定义SurfaceView !!!):
公共类MySurfaceView扩展SurfaceView实现SurfaceHolder.Callback,MediaPlayer.OnCompletionListener { 私人位图图像;
私人的MediaPlayer媒体播放器;
私人列表< MySurfaceListener> objectsToCall =新的ArrayList<>(); 公共MySurfaceView(上下文的背景下){
超级(上下文);
。getHolder()的addCallback(本);
} 公共无效addOnPlayingFinishedListener(MySurfaceListener监听){
objectsToCall.add(监听);
} 公共无效notifyAllOnPlayingFinishedListener(){
对于(MySurfaceListener L:objectsToCall){
l.onMediaPlayFinished();
}
} 公共静态INT calculateInSampleSize(BitmapFactory.Options选项,诠释reqWidth,诠释reqHeight){
// Helper方法来缩小图像文件
} 公共静态位图德codeSampledBitmapFromFile(字符串路径,INT reqWidth,诠释reqHeight){ //为图像文件的另一种辅助方法,
} 公共无效的drawImage(字符串路径,最终诠释DURATION毫秒){
this.image =去codeSampledBitmapFromFile(路径,1920,1080);
帆布帆布= NULL;
尝试{
帆布= getHolder()lockCanvas(空)。
同步(getHolder()){
的onDraw(帆布);
}
}赶上(例外五){
e.printStackTrace();
} {最后
如果(帆布!= NULL){
。getHolder()unlockCanvasAndPost(画布);
}
image.recycle();
图像= NULL;
} 螺纹showPictureTimer =新主题(新的Runnable(){
@覆盖
公共无效的run(){
尝试{
视频下载(DURATION毫秒);
}赶上(InterruptedException的E){
e.printStackTrace();
}
}
});
showPictureTimer.start();
尝试{
showPictureTimer.join();
}赶上(InterruptedException的E){
e.printStackTrace();
}
notifyAllOnPlayingFinishedListener();
} 公共无效的playVideo(字符串路径){
尝试{
媒体播放器=新的MediaPlayer();
mediaPlayer.setOnCompletionListener(本);
mediaPlayer.setDisplay(getHolder());
mediaPlayer.setDataSource(路径);
媒体播放器prepare()。
mediaPlayer.start();
}赶上(抛出:IllegalArgumentException五){
Log.d(MyMediaPlayerControl,e.getMessage());
}赶上(IllegalStateException异常五){
Log.d(MyMediaPlayerControl,e.getMessage());
}赶上(IOException异常五){
Log.d(MyMediaPlayerControl,e.getMessage());
}
} @覆盖
保护无效的onDraw(帆布油画){
super.onDraw(画布);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(this.image,0,0,新的油漆());
} 公共无效surfaceChanged(SurfaceHolder为arg0,ARG1 INT,INT ARG2,诠释ARG3){
Log.e(对myApp,surfaceChanged);
} 公共无效surfaceCreated(SurfaceHolder为arg0){
Log.e(对myApp,surfaceCreated);
} 公共无效surfaceDestroyed(SurfaceHolder为arg0){
Log.e(对myApp,surfaceDestroyed);
} @覆盖
公共无效onCompletion(MediaPlayer的MP){
如果(媒体播放器!= NULL){
mediaPlayer.stop();
mediaPlayer.release();
媒体播放器= NULL;
}
notifyAllOnPlayingFinishedListener();
}
}
和其中给出了文件路径的表面视图,用于播放(不应是问题)的螺纹
公共类MediaControlThread继承Thread实现MySurfaceListener {
公共静态列表<串GT; medialist中=新的ArrayList<串GT;();
MyMediaActivity活动;
私人MySurfaceView surfaceView;
私人INT currentVideo = 0; 公共MediaControlThread(MyMediaActivity活动){
this.activity =活动;
this.surfaceView = activity.getSurfaceView();
this.surfaceView.addOnPlayingFinishedListener(本);
} @覆盖
公共无效的run(){
尝试{
而(mediaList.size()== 0){
视频下载(1000);
}
视频下载(3000);
}赶上(InterruptedException的E){
e.printStackTrace();
}
playMedia(mediaList.get(currentVideo));
} 私人无效playMedia(字符串mediaPath){
如果(checkFileForImage(mediaPath)){
surfaceView.drawImage(mediaPath,2000年);
}其他{
surfaceView.playVideo(mediaPath);
}
} 私人布尔checkFileForImage(字符串文件名){
字符串文件= fileName.toLowerCase();
返回file.endsWith(JPG)||
file.endsWith(IMG)||
file.endsWith(BMP)||
file.endsWith(JPEG)||
file.endsWith(。ICO)||
file.endsWith(TIF。);
} @覆盖
公共无效onMediaPlayFinished(){
surfaceView.invalidate();
surfaceView.destroyDrawingCache();
currentVideo ++;
如果(currentVideo> mediaList.size() - 1){
currentVideo = 0;
}
playMedia(mediaList.get(currentVideo));
}
}
这是不幸的是,预期的行为。由于Android的一个怪癖,一旦你画在地面与帆布你不能做任何事情。
您有三种选择:
- 与OpenGL ES的,而不是画布绘制图像。一旦分离GLES你可以回去显示视频。
- present图像作为单帧视频。这工作得很好像清屏琐碎的事情,但对于动态内容的糟糕的选择。
- 使用一个的FrameLayout叠加一个ImageView的或自定义视图。显示视图时要显示的图像,将其隐藏,否则。只要表面上是在默认Z-深度,ImageView的会出现在它的面前,并掩盖它。
I want to play a video after a couple of images in the same SurfaceView. If I show images AFTER videos, everything works fine. But if I want to play a video after the images, the SurfaceView stays blank (black). Can anyone help? It seems to be a problem of clearing or resetting the SurfaceView!
The code of the SurfaceView (custom SurfaceView!!!):
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, MediaPlayer.OnCompletionListener {
private Bitmap image;
private MediaPlayer mediaPlayer;
private List<MySurfaceListener> objectsToCall = new ArrayList<>();
public MySurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
}
public void addOnPlayingFinishedListener(MySurfaceListener listener) {
objectsToCall.add(listener);
}
public void notifyAllOnPlayingFinishedListener() {
for(MySurfaceListener l : objectsToCall) {
l.onMediaPlayFinished();
}
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Helper method to scale down the image files
}
public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) {
// Another helper method for the image files
}
public void drawImage(String path, final int durationMs) {
this.image = decodeSampledBitmapFromFile(path, 1920, 1080);
Canvas canvas = null;
try {
canvas = getHolder().lockCanvas(null);
synchronized (getHolder()) {
onDraw(canvas);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null) {
getHolder().unlockCanvasAndPost(canvas);
}
image.recycle();
image = null;
}
Thread showPictureTimer = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(durationMs);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
showPictureTimer.start();
try {
showPictureTimer.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyAllOnPlayingFinishedListener();
}
public void playVideo(String path) {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setDisplay(getHolder());
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IllegalArgumentException e) {
Log.d("MyMediaPlayerControl", e.getMessage());
} catch (IllegalStateException e) {
Log.d("MyMediaPlayerControl", e.getMessage());
} catch (IOException e) {
Log.d("MyMediaPlayerControl", e.getMessage());
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(this.image, 0, 0, new Paint());
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
Log.e("myApp", "surfaceChanged");
}
public void surfaceCreated(SurfaceHolder arg0) {
Log.e("myApp", "surfaceCreated");
}
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.e("myApp", "surfaceDestroyed");
}
@Override
public void onCompletion(MediaPlayer mp) {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
notifyAllOnPlayingFinishedListener();
}
}
And the thread which gives the file paths to the surface view for playing (should not be the problem):
public class MediaControlThread extends Thread implements MySurfaceListener {
public static List<String> mediaList = new ArrayList<String>();
MyMediaActivity activity;
private MySurfaceView surfaceView;
private int currentVideo = 0;
public MediaControlThread(MyMediaActivity activity) {
this.activity = activity;
this.surfaceView = activity.getSurfaceView();
this.surfaceView.addOnPlayingFinishedListener(this);
}
@Override
public void run() {
try {
while(mediaList.size() == 0) {
Thread.sleep(1000);
}
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
playMedia(mediaList.get(currentVideo));
}
private void playMedia(String mediaPath) {
if(checkFileForImage(mediaPath)) {
surfaceView.drawImage(mediaPath, 2000);
} else {
surfaceView.playVideo(mediaPath);
}
}
private boolean checkFileForImage(String fileName) {
String file = fileName.toLowerCase();
return file.endsWith(".jpg") ||
file.endsWith(".img") ||
file.endsWith(".bmp") ||
file.endsWith(".jpeg") ||
file.endsWith(".ico") ||
file.endsWith(".tif");
}
@Override
public void onMediaPlayFinished() {
surfaceView.invalidate();
surfaceView.destroyDrawingCache();
currentVideo++;
if (currentVideo > mediaList.size() - 1) {
currentVideo = 0;
}
playMedia(mediaList.get(currentVideo));
}
}
That is, unfortunately, the expected behavior. Due to a quirk in Android, once you've drawn on a Surface with Canvas you can't do anything else.
You have three choices:
- Draw the image with OpenGL ES rather than Canvas. Once you detach GLES you can go back to showing videos.
- Present the image as a single-frame video. This works nicely for trivial things like blanking the screen, but is a poor choice for dynamic content.
- Use a FrameLayout to overlay an ImageView or custom View. Show the View when you want to show an image, hide it otherwise. So long as the Surface is at the default Z-depth, the ImageView will appear in front of it and obscure it.
这篇关于Android的SurfaceView:图像显示后视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!