简体   繁体   English

使用OpenGL和MediaCodec播放视频

[英]Playing Video with OpenGL and MediaCodec

I'm trying to play the same video at the same time in two different textureviews. 我试图在两个不同的textureviews中同时播放同一视频。 I've used code from grafika (MoviePlayer and ContinuousCaptureActivity) to try to get it to work (thanks fadden). 我使用了来自grafika的代码(MoviePlayer和ContinuousCaptureActivity)来尝试使其工作(感谢fadden)。 To make the problem simpler, I'm trying to do it with just one TextureView first. 为了使问题更简单,我尝试首先仅使用一个TextureView来完成。

At the moment I've created a TextureView, and once it get a SurfaceTexture, I create a WindowSurface and make it current. 目前,我已经创建了TextureView,并且一旦获得SurfaceTexture,就创建了WindowSurface并将其设置为当前状态。 Then I generate a TextureID generated using a FullFrameRect object. 然后,我生成一个使用FullFrameRect对象生成的TextureID。

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int
        width, int height) {
    mSurfaceTexture = surface;
    mEGLCore = new EglCore(null, EglCore.FLAG_TRY_GLES3);
    Log.d("EglCore", "EGL core made");
    mDisplaySurface = new WindowSurface(mEGLCore, mSurfaceTexture);
    mDisplaySurface.makeCurrent();
    Log.d("DisplaySurface", "mDisplaySurface made");
    mFullFrameBlit = new FullFrameRect(new Texture2dProgram(Texture2dProgram.ProgramType.TEXTURE_EXT));
    mTextureID = mFullFrameBlit.createTextureObject();

    //mSurfaceTexture.attachToGLContext(mTextureID);
    clickPlayStop(null);
}

Then I get an off-screen SurfaceTexture, link it with the TextureID that I got above and create a surface to pass to a MoviePlayer thus: 然后,获得屏幕外的SurfaceTexture,将其与上方的TextureID链接,并创建一个表面以传递给MoviePlayer:

public void clickPlayStop(@SuppressWarnings("unused") View unused) {
    if (mShowStopLabel) {
        Log.d(TAG, "stopping movie");
        stopPlayback();
        // Don't update the controls here -- let the task thread do it after the movie has
        // actually stopped.
        //mShowStopLabel = false;
        //updateControls();
    } else {
        if (mPlayTask != null) {
            Log.w(TAG, "movie already playing");
            return;
        }
        Log.d(TAG, "starting movie");
        SpeedControlCallback callback = new SpeedControlCallback();
        callback.setFixedPlaybackRate(24);

        MoviePlayer player = null;
        MovieTexture = new SurfaceTexture(mTextureID);
        MovieTexture.setOnFrameAvailableListener(this);
        Surface surface = new Surface(MovieTexture);
        try {
            player = new MoviePlayer(surface, callback, this);//TODO
        } catch (IOException ioe) {
            Log.e(TAG, "Unable to play movie", ioe);

            return;
        }

        adjustAspectRatio(player.getVideoWidth(), player.getVideoHeight());

        mPlayTask = new MoviePlayer.PlayTask(player, this);
        mPlayTask.setLoopMode(true);


        mShowStopLabel = true;
        mPlayTask.execute();
    }
}

The idea is that the SurfaceTexture gets a raw frame which I can use as an OES_external texture to sample from with OpenGL. 这个想法是,SurfaceTexture获得了一个原始帧,我可以将其用作OES_external纹理以使用OpenGL进行采样。 Then I can call DrawFrame() from my EGLContext after setting my WindowSurface as current. 然后,在将WindowSurface设置为当前值后,我可以从EGLContext调用DrawFrame()。

private void drawFrame() {
    Log.d(TAG, "drawFrame");
    if (mEGLCore == null) {
        Log.d(TAG, "Skipping drawFrame after shutdown");
        return;
    }

    // Latch the next frame from the camera.
    mDisplaySurface.makeCurrent();
    MovieTexture.updateTexImage();
    MovieTexture.getTransformMatrix(mTransformMatrix);

    // Fill the WindowSurface with it.
    int viewWidth = mTextureView.getWidth();
    int viewHeight = mTextureView.getHeight();
    GLES20.glViewport(0, 0, viewWidth, viewHeight);
    mFullFrameBlit.drawFrame(mTextureID, mTransformMatrix);
    mDisplaySurface.swapBuffers();
}

If I wanted to do it with 2 TextureViews, the idea would be to call makeCurrent() and draw into each buffer for each view, then call swapBuffers() after the drawing is done. 如果我想使用2个TextureViews进行处理,则想法是调用makeCurrent()并为每个视图绘制每个缓冲区,然后在绘制完成后调用swapBuffers()。

This is what I want to do, but I am pretty sure this is not what my code is actually doing. 这是我想做的,但是我很确定这不是我的代码实际在做的。 Could somebody help me understand what I need to change to make it work? 有人可以帮助我了解我需要进行哪些更改才能使其正常工作吗?

@Fadden @Fadden

Update: This is interesting. 更新:这很有趣。 I changed the code in onSurfaceTextureAvailable to this: 我将onSurfaceTextureAvailable中的代码更改为此:

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int
        width, int height) {
    mSurfaceTexture = surface;
    TextureHeight = height;
    TextureWidth = width;
    //mEGLCore = new EglCore(null, EglCore.FLAG_TRY_GLES3);
    Log.d("EglCore", "EGL core made");
    //mDisplaySurface = new WindowSurface(mEGLCore, mSurfaceTexture);
    //mDisplaySurface.makeCurrent();
    Log.d("DisplaySurface", "mDisplaySurface made");
    //mFullFrameBlit = new FullFrameRect(new Texture2dProgram(Texture2dProgram.ProgramType.OPENGL_TEST));
    //mTextureID = mFullFrameBlit.createTextureObject();
    //clickPlayStop(null);


    // Fill the SurfaceView with it.
    //int viewWidth = width;
    //int viewHeight = height;
    //GLES20.glViewport(0, 0, viewWidth, viewHeight);
    //mFullFrameBlit.drawFrame(mTextureID, mTransformMatrix);
    //mFullFrameBlit.openGLTest();
    //mFullFrameBlit.testDraw(mDisplaySurface.getHeight(),mDisplaySurface.getWidth());
    //mDisplaySurface.swapBuffers();
}

So, it shouldn't call anything else, just show the empty TextureView - and this is what I see... 因此,它不应该调用其他任何东西,只显示空的TextureView-这就是我所看到的...

空TextureView

Thanks to Fadden for the help. 感谢Fadden的帮助。

So there seemed to be some unknown issue that was resolved when I used a new thread to decode and produce the frames. 因此,当我使用新线程解码并生成帧时,似乎已经解决了一些未知问题。 I haven't found out what caused the original problem, but I have found a way around it. 我还没有找到导致最初问题的原因,但是我找到了解决之道。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM