上一篇是c代码版,想想还是写个java版,毕竟在java上进行很多操作比用c代码编写再编译来的方便很多,比如读取图片,添加gif之类的。
效果就不演示了,和上一篇一样我只加了个黑白滤镜,参考的还是这篇让IjkPlayer支持插入自定义的GPU滤镜,可能是版本问题吧,有些方法是不一样的,我的ijkplayer版本是0.8.4,开始改代码
在ijkmedia/ijksdl/gles2/internal.h的IJK_GLES2_Renderer结构体内添加
typedef struct IJK_GLES2_Renderer
{
...//省略代码
int has_filter;
void (* func_onCreated)(void);
void (* func_onSizeChanged)(int width,int height);
void (* func_onDrawFrame)(int textureId);
void (* func_onTexcoords)(float *texcoords);
void (* func_onVertices)(float *vertices);
void (* func_onRelease)(void);
int view_width;
int view_height;
GLuint frame_buffers[1];
GLuint frame_textures[1];
GLfloat texcoords_test[8];
GLfloat vertices_test[8];
} IJK_GLES2_Renderer;
在ijkmedia/ijksdl/ijksdl_vout.h的SDL_Vout和SDL_VoutOverlay结构体内添加
struct SDL_VoutOverlay {
...//省略代码
int has_filter;
void (* func_onCreated)(void);
void (* func_onSizeChanged)(int width,int height);
void (* func_onDrawFrame)(int textureId);
void (* func_onTexcoords)(float *texcoords);
void (* func_onVertices)(float *vertices);
void (* func_onRelease)(void);
};
struct SDL_Vout {
...//省略代码
int has_filter;
void (* func_onCreated)(void);
void (* func_onSizeChanged)(int width,int height);
void (* func_onDrawFrame)(int textureId);
void (* func_onTexcoords)(float *texcoords);
void (* func_onVertices)(float *vertices);
void (* func_onRelease)(void);
};
在ijkmedia/ijkplayer/android/ijkplayer_android.h添加函数
void ijkmp_android_set_filter(IjkMediaPlayer *mp,int has_filter,void *onCreated,void *onSizeChanged,void *onDrawFrame,void *onTexcoords,void *onVertices,void *onRelease);
在ijkmedia/ijkplayer/android/ijkplayer_android.c内添加函数
void ijkmp_android_set_filter(IjkMediaPlayer *mp,int has_filter,void *onCreated,void *onSizeChanged,void *onDrawFrame,void *onTexcoords,void *onVertices,void *onRelease){
mp->ffplayer->vout->has_filter = has_filter;
if(has_filter == 1){
mp->ffplayer->vout->func_onCreated=onCreated;
mp->ffplayer->vout->func_onSizeChanged=onSizeChanged;
mp->ffplayer->vout->func_onDrawFrame=onDrawFrame;
mp->ffplayer->vout->func_onTexcoords=onTexcoords;
mp->ffplayer->vout->func_onVertices=onVertices;
mp->ffplayer->vout->func_onRelease=onRelease;
}
}
在ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c的func_create_overlay()函数内添加
static SDL_VoutOverlay *func_create_overlay(int width, int height, int frame_format, SDL_Vout *vout)
{
SDL_LockMutex(vout->mutex);
SDL_VoutOverlay *overlay = func_create_overlay_l(width, height, frame_format, vout);
overlay->has_filter=vout->has_filter;
overlay->func_onCreated=vout->func_onCreated;
overlay->func_onSizeChanged=vout->func_onSizeChanged;
overlay->func_onDrawFrame=vout->func_onDrawFrame;
overlay->func_onTexcoords=vout->func_onTexcoords;
overlay->func_onVertices=vout->func_onVertices;
overlay->func_onRelease=vout->func_onRelease;
SDL_UnlockMutex(vout->mutex);
return overlay;
}
在ijkmedia/ijksdl/gles2/renderer.c的IJK_GLES2_Renderer_create()函数内添加
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay)
{
...//省略代码
renderer->has_filter=overlay->has_filter;
renderer->func_onCreated=overlay->func_onCreated;
renderer->func_onSizeChanged=overlay->func_onSizeChanged;
renderer->func_onDrawFrame=overlay->func_onDrawFrame;
renderer->func_onTexcoords=overlay->func_onTexcoords;
renderer->func_onVertices=overlay->func_onVertices;
renderer->func_onRelease=overlay->func_onRelease;
return renderer;
}
然后在ijkmedia/ijkplayer/android/ijkplayer_jni.c内添加代码
static JNIEnv * mEnv;
static jmethodID onCreatedMethod;
static jmethodID onSizeChangedMethod;
static jmethodID onDrawFrameMethod;
static jmethodID onTexcoordsMethod;
static jmethodID onVerticesMethod;
static jmethodID onReleaseMethod;
void onCreated(){
if(!mEnv){
(*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
jclass filterClass=(*mEnv)->GetObjectClass(mEnv,mFilter);
onCreatedMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onCreated","()V");
onSizeChangedMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onSizeChanged","(II)V");
onDrawFrameMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onDrawFrame","(I)V");
onTexcoordsMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onTexcoords","([F)V");
onVerticesMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onVertices","([F)V");
onReleaseMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onRelease","()V");
(*g_jvm)->DetachCurrentThread(g_jvm);
}
if(onCreatedMethod){
(*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
(*mEnv)->CallVoidMethod(mEnv,mFilter,onCreatedMethod);
(*g_jvm)->DetachCurrentThread(g_jvm);
}
}
void onSizeChanged(int width,int height){
if(onSizeChangedMethod){
(*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
(*mEnv)->CallVoidMethod(mEnv,mFilter,onSizeChangedMethod,width,height);
(*g_jvm)->DetachCurrentThread(g_jvm);
}
}
void onDrawFrame(int textureId){
if(onDrawFrameMethod){
(*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
(*mEnv)->CallVoidMethod(mEnv,mFilter,onDrawFrameMethod,textureId);
(*g_jvm)->DetachCurrentThread(g_jvm);
}
}
void onTexcoords(float *texcoords){
if(onTexcoordsMethod){
(*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
jfloatArray array = (*mEnv)->NewFloatArray(mEnv,8);
(*mEnv)->SetFloatArrayRegion(mEnv,array, 0, 8, texcoords);
(*mEnv)->CallVoidMethod(mEnv,mFilter,onTexcoordsMethod,array);
(*mEnv)->DeleteLocalRef(mEnv, array);
(*g_jvm)->DetachCurrentThread(g_jvm);
}
}
void onVertices(float *vertices){
if(onVerticesMethod){
(*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
jfloatArray array = (*mEnv)->NewFloatArray(mEnv,8);
(*mEnv)->SetFloatArrayRegion(mEnv,array, 0, 8, vertices);
(*mEnv)->CallVoidMethod(mEnv,mFilter,onVerticesMethod,array);
(*mEnv)->DeleteLocalRef(mEnv, array);
(*g_jvm)->DetachCurrentThread(g_jvm);
}
}
void onRelease(){
if(onReleaseMethod){
(*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
(*mEnv)->CallVoidMethod(mEnv,mFilter,onReleaseMethod);
(*g_jvm)->DetachCurrentThread(g_jvm);
}
}
static void IjkMediaPlayer_native_setGLFilter(JNIEnv *env,jobject thiz,jobject filter)
{
if(mFilter){
(*env)->DeleteGlobalRef(env,mFilter);
}
IjkMediaPlayer *mp = jni_get_media_player(env, thiz);
if(filter!=NULL){
mFilter=(*env)->NewGlobalRef(env,filter);
ijkmp_android_set_filter(mp,1,onCreated,onSizeChanged,onDrawFrame,onTexcoords,onVertices,onRelease);
}else{
ijkmp_android_set_filter(mp,0,NULL,NULL,NULL,NULL,NULL,NULL);
}
}
在g_methods[]内添加
{ "_setGLFilter", "(Ltv/danmaku/ijk/media/player/IjkFilter;)V", (void *) IjkMediaPlayer_native_setGLFilter },
在函数IjkMediaPlayer_release()内添加
if(mFilter){
(*env)->DeleteGlobalRef(env,mFilter);
mFilter=NULL;
}
好了,接下来就是改ijkmedia/ijksdl/gles2/renderer.c的代码了,从上到下把要修改的地方都说一下
在IJK_GLES2_Renderer_reset()函数内添加
void IJK_GLES2_Renderer_reset(IJK_GLES2_Renderer *renderer)
{
...// 省略代码
if(renderer->frame_textures){
glDeleteTextures(1, renderer->frame_textures);
renderer->frame_textures[0] = 0;
}
if(renderer->frame_buffers){
glDeleteBuffers(1,renderer->frame_buffers);
renderer->frame_buffers[0] = 0;
}
if(renderer->has_filter){
renderer->func_onRelease();
}
}
在IJK_GLES2_Renderer_create_base()内添加
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source)
{
...//省略代码
renderer->texcoords_test[0] = 0.0f;
renderer->texcoords_test[1] = 1.0f;
renderer->texcoords_test[2] = 1.0f;
renderer->texcoords_test[3] = 1.0f;
renderer->texcoords_test[4] = 0.0f;
renderer->texcoords_test[5] = 0.0f;
renderer->texcoords_test[6] = 1.0f;
renderer->texcoords_test[7] = 0.0f;
renderer->vertices_test[0] = -1.0f;
renderer->vertices_test[1] = -1.0f;
renderer->vertices_test[2] = 1.0f;
renderer->vertices_test[3] = -1.0f;
renderer->vertices_test[4] = -1.0f;
renderer->vertices_test[5] = 1.0f;
renderer->vertices_test[6] = 1.0f;
renderer->vertices_test[7] = 1.0f;
return renderer;
...//省略代码
return NULL;
}
在IJK_GLES2_Renderer_Vertices_apply()添加
static void IJK_GLES2_Renderer_Vertices_apply(IJK_GLES2_Renderer *renderer)
{
...//省略代码
if(renderer->has_filter){
renderer->func_onVertices(renderer->vertices);
}
}
修改IJK_GLES2_Renderer_Vertices_reloadVertex()
static void IJK_GLES2_Renderer_Vertices_reloadVertex(IJK_GLES2_Renderer *renderer)
{
glVertexAttribPointer(renderer->av4_position, 2, GL_FLOAT, GL_FALSE, 0, renderer->vertices_test); IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)");
glEnableVertexAttribArray(renderer->av4_position); IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)");
}
在IJK_GLES2_Renderer_TexCoords_cropRight()添加
static void IJK_GLES2_Renderer_TexCoords_cropRight(IJK_GLES2_Renderer *renderer, GLfloat cropRight)
{
...//省略代码
if(renderer->has_filter){
renderer->func_onTexcoords(renderer->texcoords);
}
}
修改IJK_GLES2_Renderer_TexCoords_reloadVertex()
static void IJK_GLES2_Renderer_TexCoords_reloadVertex(IJK_GLES2_Renderer *renderer)
{
glVertexAttribPointer(renderer->av2_texcoord, 2, GL_FLOAT, GL_FALSE, 0, renderer->texcoords_test); IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)");
glEnableVertexAttribArray(renderer->av2_texcoord); IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)");
}
还是那句我忘了IJK_GLES2_Renderer_use()内改了什么就直接贴全部代码
GLboolean IJK_GLES2_Renderer_use(IJK_GLES2_Renderer *renderer)
{
if (!renderer)
return GL_FALSE;
assert(renderer->func_use);
if (!renderer->func_use(renderer))
return GL_FALSE;
IJK_GLES2_Renderer_TexCoords_reset(renderer);
IJK_GLES2_Renderer_Vertices_reset(renderer);
return GL_TRUE;
}
差点忘了IJK_GLES2_Renderer_set_view_size()了,在ijkmedia/ijksdl/ijksdl_gles2.h内添加函数
void IJK_GLES2_Renderer_set_view_size(IJK_GLES2_Renderer *renderer,int width,int height);
在ijkmedia/ijksdl/ijksdl_egl.c的IJK_EGL_prepareRenderer()内添加代码
static EGLBoolean IJK_EGL_prepareRenderer(IJK_EGL* egl, SDL_VoutOverlay *overlay)
{
...//省略代码
IJK_GLES2_Renderer_set_view_size(opaque->renderer,egl->width, egl->height);
return EGL_TRUE;
}
在ijkmedia/ijksdl/gles2/renderer.c内添加
void IJK_GLES2_Renderer_set_view_size(IJK_GLES2_Renderer *renderer,int width,int height){
renderer->view_width = width;
renderer->view_height = height;
}
回到renderer.c,最后改IJK_GLES2_Renderer_renderOverlay()
GLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
GLsizei visible_width = renderer->frame_width;
GLsizei visible_height = renderer->frame_height;
if (overlay) {
visible_width = overlay->w;
visible_height = overlay->h;
if (renderer->frame_width != visible_width ||
renderer->frame_height != visible_height ||
renderer->frame_sar_num != overlay->sar_num ||
renderer->frame_sar_den != overlay->sar_den) {
renderer->frame_width = visible_width;
renderer->frame_height = visible_height;
renderer->frame_sar_num = overlay->sar_num;
renderer->frame_sar_den = overlay->sar_den;
renderer->vertices_changed = 1;
}
renderer->last_buffer_width = renderer->func_getBufferWidth(renderer, overlay);
if (!renderer->func_uploadTexture(renderer, overlay))
return GL_FALSE;
} else {
// NULL overlay means force reload vertice
renderer->vertices_changed = 1;
}
GLsizei buffer_width = renderer->last_buffer_width;
if (renderer->vertices_changed ||
(buffer_width > 0 &&
buffer_width > visible_width &&
buffer_width != renderer->buffer_width &&
visible_width != renderer->visible_width)){
renderer->vertices_changed = 0;
IJK_GLES2_Renderer_Vertices_apply(renderer);
renderer->buffer_width = buffer_width;
renderer->visible_width = visible_width;
GLsizei padding_pixels = buffer_width - visible_width;
GLfloat padding_normalized = ((GLfloat)padding_pixels) / buffer_width;
IJK_GLES2_Renderer_TexCoords_reset(renderer);
IJK_GLES2_Renderer_TexCoords_cropRight(renderer, padding_normalized);
}
if (!renderer || !renderer->func_uploadTexture)
return GL_FALSE;
if(renderer->has_filter&&!renderer->frame_buffers[0]&&renderer->frame_width>0&&renderer->frame_height>0){
glGenTextures(1,renderer->frame_textures);
glBindTexture(GL_TEXTURE_2D,renderer->frame_textures[0]);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,renderer->frame_width,renderer->frame_height,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D,0);
glGenFramebuffers(1,renderer->frame_buffers);
glBindFramebuffer(GL_FRAMEBUFFER,renderer->frame_buffers[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,renderer->frame_textures[0],0);
glBindFramebuffer(GL_FRAMEBUFFER,0);
renderer->func_onCreated();
renderer->func_onSizeChanged(renderer->view_width, renderer->view_height);
}
if(renderer->has_filter&&renderer->frame_buffers[0]){
glBindFramebuffer(GL_FRAMEBUFFER,renderer->frame_buffers[0]);
}
renderer->func_use(renderer);
glViewport(0, 0, renderer->frame_width, renderer->frame_height); IJK_GLES2_checkError_TRACE("glViewport");
glClear(GL_COLOR_BUFFER_BIT); IJK_GLES2_checkError_TRACE("glClear");
IJK_GLES_Matrix modelViewProj;
IJK_GLES2_loadOrtho(&modelViewProj, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
glUniformMatrix4fv(renderer->um4_mvp, 1, GL_FALSE, modelViewProj.m); IJK_GLES2_checkError_TRACE("glUniformMatrix4fv(um4_mvp)");
IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer);
IJK_GLES2_Renderer_Vertices_reloadVertex(renderer);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); IJK_GLES2_checkError_TRACE("glDrawArrays");
if(renderer->has_filter&&renderer->frame_buffers[0]){
glBindFramebuffer(GL_FRAMEBUFFER,0);
renderer->func_onDrawFrame(renderer->frame_textures[0]);
}
return GL_TRUE;
}
好了,可能忘了一些代码,我会在最后放上源码,可以下载来看看
接下来就是改java代码了,java还是很简单的,在tv/danmaku/ijk/media/player文件夹下添加个类
public interface IjkFilter {
void onCreated();
void onSizeChanged(int width,int height);
void onDrawFrame(int textureId);
void onTexcoords(float[] texcoords);
void onVertices(float[] vertices);
void onRelease();
}
在IjkMediaPlayer.java内添加
public void setFilter(IjkFilter filter){
_setGLFilter(filter);
}
private native void _setGLFilter(IjkFilter filter);
好了,这样就可以实现滤镜了,用法和GLSurfaceView.Renderer一样,贴我的实现代码,先贴shader代码
bitmap_vertext_shader.glsl
precision highp float;
varying highp vec2 vTexCoord;
attribute highp vec4 aPosition;
attribute highp vec2 aTexCoord;
void main()
{
vTexCoord = vec2(aTexCoord.x,1.0-aTexCoord.y);
gl_Position = aPosition;
}
bitmap_fragment_sharder.glsl
precision highp float;
varying highp vec2 vTexCoord;
uniform lowp sampler2D sTexture;
void main()
{
lowp vec3 rgb = texture2D(sTexture, vTexCoord).rgb;
gl_FragColor = vec4(0.299*rgb.r+0.587*rgb.g+0.114*rgb.b);
}
建一个读取program的类
ShaderUtils.java
public class ShaderUtils {
private static final String TAG = "ShaderUtils";
public static void checkGlError(String label) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, label + ": glError " + error);
throw new RuntimeException(label + ": glError " + error);
}
}
public static int createProgram(String vertexSource, String fragmentSource) {
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) {
return 0;
}
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if (pixelShader == 0) {
return 0;
}
int program = GLES20.glCreateProgram();
if (program != 0) {
GLES20.glAttachShader(program, vertexShader);
checkGlError("glAttachShader");
GLES20.glAttachShader(program, pixelShader);
checkGlError("glAttachShader");
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
Log.e(TAG, "Could not link program: ");
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;
}
public static int loadShader(int shaderType, String source) {
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
int[] compiled = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e(TAG, "Could not compile shader " + shaderType + ":");
Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
shader = 0;
}
}
return shader;
}
public static String readRawTextFile(Context context, int resId) {
InputStream inputStream = context.getResources().openRawResource(resId);
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
reader.close();
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
然后是我的滤镜实现类
GLRenderer.java
public class GLRenderer implements IjkFilter {
private Context context;
private FloatBuffer vertexBuffer;
private FloatBuffer textureVertexBuffer;
private int programId = 0;
private int aPositionHandle;
private int uTextureSamplerHandle;
private int aTextureCoordHandle;
public GLRenderer(Context context){
this.context = context;
final float[] vertexData = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
};
final float[] textureVertexData = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
vertexBuffer.position(0);
textureVertexBuffer = ByteBuffer.allocateDirect(textureVertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(textureVertexData);
textureVertexBuffer.position(0);
}
@Override
public void onCreated() {
String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.bitmap_vertext_shader);
String fragmentShader = ShaderUtils.readRawTextFile(context, R.raw.bitmap_fragment_sharder);
programId = ShaderUtils.createProgram(vertexShader, fragmentShader);
aPositionHandle = GLES20.glGetAttribLocation(programId, "aPosition");
uTextureSamplerHandle = GLES20.glGetUniformLocation(programId, "sTexture");
aTextureCoordHandle = GLES20.glGetAttribLocation(programId, "aTexCoord");
}
private Rect rect = new Rect();
@Override
public void onSizeChanged(int width, int height) {
rect.left = 0;
rect.top = 0;
rect.right = width;
rect.bottom = height;
}
@Override
public void onDrawFrame(int textureId) {
GLES20.glUseProgram(programId);
GLES20.glViewport(0,0,rect.right,rect.bottom);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnableVertexAttribArray(aPositionHandle);
GLES20.glVertexAttribPointer(aPositionHandle, 2, GLES20.GL_FLOAT, false,
8, vertexBuffer);
GLES20.glEnableVertexAttribArray(aTextureCoordHandle);
GLES20.glVertexAttribPointer(aTextureCoordHandle, 2, GLES20.GL_FLOAT, false, 8, textureVertexBuffer);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureId);
GLES20.glUniform1i(uTextureSamplerHandle, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
public void onTexcoords(float[] texcoords){
textureVertexBuffer.clear();
textureVertexBuffer.put(texcoords);
textureVertexBuffer.position(0);
}
public void onVertices(float[] vertices){
vertexBuffer.clear();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
}
public void onRelease(){
if(programId != 0){
GLES20.glDeleteProgram(programId);
}
}
}
最后在IjkMediaPlayer初始化后调用setFilter函数
GLRenderer renderer = new GLRenderer(getContext());
ijkMediaPlayer.setFilter(renderer);
同样的要开启opengl渲染
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", "fcc-_es2");
源码:百度云,里面也有.so和.jar文件,不过还是推荐自己修改编译,我只是简单的测试几下,应该bug还挺多
密码:26dk
用官方的列子测试了几下,像onRelease()都不会调用,也不知道ijkplayer是怎么释放的,看来还是要研究研究