本文以 OpenGL ES 範例 - GLSurfaceView 實作 與 影像播放器實作 - 使用 MediaCodec 類别 為基礎實作影像播放器 (不含聲音). MediaCodc 輸出影像至使用SurfaceTexture 類別建立之 Surface.

<<SurfaceTexture>>

建立 SurfaceTexture, 建構元需要傳入由 glGenTextures() 產生的 texturehandler. 再將 SurfaceTexture 傳入 Surface 建構元.

配置 SurafceTexture.OnFrameAvailableListener(), OnFrameAvailable() 將在 MediaCodec.releaseOutputBuffer() 後觸發.

if (id == R.id.action_play) {
// Create SurfaceTexture and set callback for frame update event triggered by
// MediaCodec releaseOutputBuffer()
if (surfaceTexture == null) {
surfaceTexture = new SurfaceTexture(glRenderer.getTextureHandle());
surfaceTexture.setOnFrameAvailableListener(this);
surface = new Surface(surfaceTexture);
}
sampleMediaCodec.play(this, surface, "sdcard/Movies/h264_720p.mp4");
}

 

此 Surface 將被配置至 MediaCodec.

decoder.configure(format, surface, null, 0 /* 0:decoder 1:encoder */);

 

呼叫 MediaCodec.releaseOutputBuffer() 觸發 OnFrameAvailable().

// outputBuffer is ready to be processed or rendered.
// If surface is SurfaceTexture, onFrameAvailable() will be called.
decoder.releaseOutputBuffer(outputBufferIndex, true /*true:render to surface*/);

OnFrameAvailable() 觸發後, 在 OnDrawFrame() 中呼叫 SurfaceTexture.updateTexImage() 使此 SurfaceTexture 的 Texture 更新.

public void onDrawFrame(GL10 gl) {
if(surfaceTexture != null) {
// Here is right context of calling SurfaceTexture.updateTexImage()
surfaceTexture.updateTexImage();
surfaceTexture = null;
}
sampleGL20Video.draw();
}

 

<<GL_TEXTURE_EXTERNAL_OES>>

在 shader 中使用 sampleExternalOES 而不是 sample2D.

private final String fragmentShaderCode =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;" +
"uniform samplerExternalOES texture;" +
"varying vec2 texCoordVar;" +
"void main() {" +
" gl_FragColor = texture2D(texture, texCoordVar);" +
"}";

 

將 GL_TEXTURE0 bind 至 GL_TEXTURE_EXTERNAL_OES.

// Assign GL_TEXTURE0 to fragment shader Sampler2D object "texture"
GLES20.glUseProgram(mProgram);
int texture;
texture = GLES20.glGetUniformLocation(mProgram, "texture");
GLES20.glUniform1i(texture, 0 /* texture unit 0 */);

// Create "One" "texture object"
GLES20.glGenTextures(1, textureHandle, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Use GL_TEXTURE_EXTERNAL_OES instead of GL_TEXTURE0 for video stream comes from SurfaceTexture
// http://developer.android.com/reference/android/graphics/SurfaceTexture.html
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureHandle[0]);

// Set up filter - GL_LINEAR for better image quality
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

<<MediaCodec 改善>>

本文並改善 ediaCodec 效能.

commit a43dce6f03f0c3c08b6db324bcefc2bca81727b4

Improvement of MediaCodec

1. Video source can be passed by caller in SampleMediaCodec constructor
2. Frame rate control able to play video in correct fps     

 

<<產生截圖>>

glReadPixels() 可取得畫面. 利用 Bitmap 類別儲存成檔案.

// Create bitmap of video returned by glReadPixels()
// Must be called in context of onFrameDraw()
private void createBitmap(String fileName) {
Bitmap videoFrame;
int size = surfaceWidth * surfaceHeight;
ByteBuffer buf = ByteBuffer.allocateDirect(size * 4);
buf.order(ByteOrder.nativeOrder());
GLES20.glReadPixels(0, 0, surfaceWidth, surfaceHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
int data[] = new int[size];
buf.asIntBuffer().get(data);
videoFrame = Bitmap.createBitmap(surfaceWidth, surfaceHeight, Bitmap.Config.ARGB_8888);
videoFrame.setPixels(data, size-surfaceWidth, -surfaceWidth, 0, 0, surfaceWidth, surfaceHeight);
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(fileName);
videoFrame.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
videoFrame.recycle();
}

 

<<原始碼>>

SampleOpenGLPlayer GitHub  

 

<<參考>>

http://developer.android.com/reference/android/graphics/SurfaceTexture.html

(完)

 

文章標籤
創作者介紹
創作者 版大 的頭像
版大

嵌入式系統

版大 發表在 痞客邦 留言(0) 人氣()