2015-10-27 1 views
2

Я хочу воспроизвести видео после нескольких изображений в том же SurfaceView. Если я показываю изображения ПОСЛЕ видео, все работает нормально. Но если я хочу воспроизвести видео после изображений, SurfaceView останется пустым (черный). Может ли кто-нибудь помочь? Кажется, что проблема очистки или сброса SurfaceView!Android SurfaceView: Показать видео после изображений

код из SurfaceView (настраиваемого 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(); 
    } 
} 

И нить, которая дает пути файлов в представлении поверхности для игры (не должно быть проблемы):

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)); 
    } 
} 

ответ

3

Это, к сожалению, ожидаемое поведение. Из-за причуды на Android, когда вы нарисовали на поверхности с Canvas, вы ничего не можете сделать.

У вас есть три варианта:

  1. Draw изображения с OpenGL ES, а не Canvas. Как только вы отсоедините GLES, вы можете вернуться к показу видео.
  2. Представьте изображение как однокадровое видео. Это хорошо работает для простых вещей, таких как гашение экрана, но это плохой выбор для динамического контента.
  3. Используйте FrameLayout для наложения ImageView или пользовательского вида. Покажите представление, когда вы хотите показать изображение, в противном случае спрячьте его. Пока поверхность находится на глубине Z по умолчанию, перед ней появится ImageView и затушевывает ее.
+0

Благодарим за предоставленную информацию, вы сохранили мой день! Я пробовал ваш третий подход и добавил ImageView рядом с SurfaceView в мой макет. В зависимости от медиа-типа я устанавливаю видимое изображение (in). ВАЖНО: никогда не устанавливайте SurfaceView невидимым/ушедшим, это приведет к разрушению SurfaceView, поэтому он больше не сможет его использовать (это была моя ошибка !!!)! –

 Смежные вопросы

  • Нет связанных вопросов^_^