2014-09-04 11 views
9

Ich habe einen Media Player erstellt, der Video auf der Oberflächenansicht spielt. Nach Abschluss des Videos bleibt der letzte Frame des Videos auf der Oberfläche. Ich möchte den Videoframe von der Oberfläche entfernen, da nach einiger Zeit ein anderes Video startet.Clear Video Frame von der Oberfläche auf Video komplett

Die Strömung des Videos ist:

JETZT: Video auf der Oberfläche -> letzter Video-Frame auf der Oberfläche -> ein weiteres Video auf der Oberfläche.

Aber die erforderliche Strömung ist:

ERFORDERLICH:Video auf der Oberfläche -> klare Oberfläche (schwarz) -> ein weiteres Video auf der Oberfläche.

kann jemand helfen, dieses Problem zu lösen.

Dank Ishan Jain

Antwort

-1

Klare Oberfläche, wenn die Wiedergabe von Video (Mediaplayer onCompletion Rückruf) abgeschlossen ist:

Canvas canvas = surfaceView.getHolder().lockCanvas(); 

    // Clear surface by drawing on it 
    canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); 

    // option 
    // canvas.drawColor(Color.BLACK); 

    surfaceView.getHolder().unlockCanvasAndPost(canvas); 

Eine weitere Option (aber ich nicht klar jetzt erinnere mich) ist Aufruf einer der MediaPlayer-Klassenfunktion, wenn onComplication() Callback aufgerufen wird:

MediaPlayer.stop(); 

// reset to clear ready to reuse state. 
MediaPlayer.reset(); 

// release all releted objects and memory 
MediaPlayer.release() 

Einer davon verursacht eine klare Oberflächenansicht. Nach release() müssen Sie erneut eine MediaPlayer Instanz erstellen.

+0

Ich habe bereits versucht und bekomme die folgende Ausnahme: ** 09-04 20: 28: 34.164: A/libc (545): Fatal Signal 11 (SIGSEGV) bei 0x5cd14000 (Code = 1), Thread 545 () ** und die Anwendung stürzt ab. –

+0

Veröffentlichen Sie die gesamte Stack-Trace und Logs von Logcat. Versuchen Sie auch, MediaPlayer.stop() und MediaPlayer.reset()/MediaPlayer.release() aufzurufen, da ich mich an einen der Funktionen erinnere, die einen klaren schwarzen Bildschirm verursachen. Ich bin sicher. – dasar

+0

Nein, keiner von ihnen funktionierte in meinem Fall. Ich habe versucht, Video auf Android 4.3 Gerät zu spielen. – Yeung

5

Sie können es mit GLES löschen. Sie können es nicht mit Canvas Zeichenbefehlen löschen, da dies verhindert, dass Sie wieder Filme auf dieser Oberfläche abspielen.

Ein Beispiel kann in Grafika 's PlayMovieSurfaceActivity Klasse gefunden werden. Die clearSurface() Methode tut dies:

EglCore eglCore = new EglCore(); 
    WindowSurface win = new WindowSurface(eglCore, surface, false); 
    win.makeCurrent(); 
    GLES20.glClearColor(0, 0, 0, 0); 
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 
    win.swapBuffers(); 
    win.release(); 
    eglCore.release(); 

Die EglCore und WindowSurface Klassen Teil Grafika sind. Das Entscheidende ist, dass es an der Oberfläche haftet, klar macht und sich dann von der Oberfläche löst. Stellen Sie sicher, dass der Videoplayer die Oberfläche freigegeben hat, bevor Sie dies tun, oder GLES kann nicht anhängen.

Wenn Sie verstehen möchten, warum die Attach/Detach-Sachen notwendig sind, siehe system-level graphics architecture doc.

+1

Gibt es eine Chance, dass dies mit API Level 15+ funktioniert? Ich habe versucht, über die EglCore-Klasse von Grafika zu portieren, und es scheint zu API-Ebene 17 gebunden. – andreimarinescu

+0

Grafika verwendet einige Funktionen mit EGL 1.4, die in API 17 hinzugefügt wurde. Ich denke, das oben genannte ist trivial genug, dass es sein sollte machbar mit EGL 1.0, aber Sie würden nur die notwendigen Bits aus dem Grafik-Code herausziehen. Wenn Sie nicht sicher sind, was die EGL 1.0/1.4-API-Unterschiede sind, wurde http://bigflake.com/mediacodec/#ExtractMpegFramesTest zweimal geschrieben, für API 16 und 17, was es leicht macht, eine Seite-an-Seite zu machen Vergleich. – fadden

+0

Das ist großartig, danke für die Hinweise @fadden! Es ist eine gute Übung für mich auch :) – andreimarinescu

8

Aufbauend auf Fadden Antwort und Andreimarinescu Frage, hier ist eine Version für API 16 und unter:

private void clearSurface(Surface surface) { 
    EGL10 egl = (EGL10) EGLContext.getEGL(); 
    EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 
    egl.eglInitialize(display, null); 

    int[] attribList = { 
      EGL10.EGL_RED_SIZE, 8, 
      EGL10.EGL_GREEN_SIZE, 8, 
      EGL10.EGL_BLUE_SIZE, 8, 
      EGL10.EGL_ALPHA_SIZE, 8, 
      EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, 
      EGL10.EGL_NONE, 0,  // placeholder for recordable [@-3] 
      EGL10.EGL_NONE 
    }; 
    EGLConfig[] configs = new EGLConfig[1]; 
    int[] numConfigs = new int[1]; 
    egl.eglChooseConfig(display, attribList, configs, configs.length, numConfigs); 
    EGLConfig config = configs[0]; 
    EGLContext context = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, new int[]{ 
      EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, 
      EGL10.EGL_NONE 
    }); 
    EGLSurface eglSurface = egl.eglCreateWindowSurface(display, config, surface, 
      new int[]{ 
        EGL14.EGL_NONE 
      }); 

    egl.eglMakeCurrent(display, eglSurface, eglSurface, context); 
    GLES20.glClearColor(0, 0, 0, 1); 
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 
    egl.eglSwapBuffers(display, eglSurface); 
    egl.eglDestroySurface(display, eglSurface); 
    egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, 
      EGL10.EGL_NO_CONTEXT); 
    egl.eglDestroyContext(display, context); 
    egl.eglTerminate(display); 
} 

recht grob, fehlt Fehlerprüfung, aber es funktioniert für mich.

+0

'EGL14.EGL_OPENGL_ES2_BIT' sollte durch' EGL10.EGL_WINDOW_BIT' ersetzt werden - 'EGL14.EGL_NONE' sollte durch' EGL10.EGL_NONE' ersetzt werden - Keine Idee, wie 'EGL14 zu ersetzen ist. EGL_CONTEXT_CLIENT_VERSION'. Derzeit benötigt Ihre Lösung API 17 ... Aber es funktioniert gut auf API 17. –

+1

Ich habe es mit API 16 kompatibel gemacht: https://gist.github.com/HugoGresse/5ca05821444353a823bb –

+0

Oh, interessant. Danke für das Update. Ich denke, wenn Sie mit SDK 17 kompilieren, können Sie dieses (ich denke) noch auf API 16 laufen lassen, weil die Konstanten zur Kompilierungszeit gefaltet werden. Nicht 100% sicher aber. – nmr

0

Ich löste das Problem auf sehr einfache Weise - einfach Surface unsichtbar machen, bis das Video vorbereitet ist. Wenn Sie einen schwarzen Bildschirm wünschen, können Sie eine schwarze Bildschirmansicht (curtainView) hinzufügen.

public void play(String path) { 
    try { 
     status = STATUS_PREPARING; 
     mSurface.setVisibility(View.INVISIBLE); 
     mCurtainView.setVisibility(View.VISIBLE); // simple black view 
     mPlayer = new MediaPlayer(); 
     if(mSurfaceHolder!=null) mPlayer.setDisplay(mSurfaceHolder); 
     mPlayer.setDataSource(path); 
     mPlayer.prepareAsync(); 
     mPlayer.setOnPreparedListener(this); 
    } catch (Exception e) { 
     return; 
    } 
} 

... 

@Override 
public void onPrepared(MediaPlayer mp) { 
    mSurface.setVisibility(View.VISIBLE); 
    if(mSurfaceHolder != null){  
     mPlayer.start(); 
     mCurtainView.setVisibility(View.GONE); 
     status = STATUS_PLAYING; 
    } else { 
     status = STATUS_DATA_PREPARED; 
    } 
} 

private final class SurfaceCallback implements Callback { 
    public void surfaceCreated(SurfaceHolder holder) { 
     mSurfaceHolder = holder; 
     mPlayer.setDisplay(holder); 
     if(status==STATUS_DATA_PREPARED){ 
      mPlayer.start(); 
      mCurtainView.setVisibility(View.GONE); 
      status = STATUS_PLAYING; 
     } 
    } 

    public void surfaceDestroyed(SurfaceHolder holder) { 
     mSurfaceHolder = null; 
    } 
    ... 
} 
3

Ich hatte ein ähnliches Problem. In meinem Fall zeigte ich eine Titelkarte, die die Videoansicht vollständig abdeckte, gefolgt vom Video selbst. Die erste Titelkarte und das Video, das folgte, waren gut. Wenn jedoch eine nachfolgende Titelkarte ausgeblendet wurde, würde der letzte Frame des vorherigen Videos blinken, bevor das nächste Video gestartet wurde. Ich habe meinem VideoView einen Info-Listener hinzugefügt, um nach dem ersten Frame-Rendering zu suchen, bevor die Titelkarte ausgeblendet wird. Dies deckt das Video ab, bis der erste korrekte Frame gerendert wurde. Ich hoffe das hilft!

mVideoView.setOnInfoListener(new MediaPlayer.OnInfoListener() 
{ 
    @Override 
    public boolean onInfo(final MediaPlayer mp, final int what, final int extra) 
    { 
     if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) 
     { 
      mTitleCardView.setVisibility(View.GONE); 

      return true; 
     } 

     return false; 
    } 
}); 
1

Ich habe das gleiche Problem. Vielleicht jemandem helfen. Ich fand Lösung hier https://stackoverflow.com/a/18906637

Ich habe Spieler in Service, in Fragmente I onComplete Rückruf habe und nach dem Video fertig:

videoHolder.setFormat(PixelFormat.TRANSPARENT); 
videoHolder.setFormat(PixelFormat.OPAQUE); 
videoService.setVideoDisplay(videoHolder); 
0

Ich habe eine Probe Problem und ich regelte es durch diese beiden Linien nach Spieler-Release mit .

surfaceViewHolder.setFormat (PixelFormat.TRANSPARENT); surfaceViewHolder.setFormat (PixelFormat.OPAQUE);