IjkPlayer 로 하여 금 사용자 정의 GPU 필 터 를 삽입 하 는 방법 을 지원 하 게 합 니 다.

최근 작업 때문에 우리 의AiyaEffectsSDK를 Ijk Player 에 삽입 하 는 예 시 를 제공 해 야 하기 때문에 Ijk Player 의 코드 를 잘 볼 수 밖 에 없습니다.Ijk Player 에 서 는 사용자 정의 GPU 필 터 를 설정 하 는 인 터 페 이 스 를 제공 하지 않 았 기 때문에 결국 스스로 손 을 써 서 풍족 하 게 먹 을 수 밖 에 없 었 다.어 쩔 수 없 이 Bilibili 가 시작 한 이 Ijk Player 플레이 어 는 정말 강하 고 코드 디자인 이 매우 뚜렷 하 며 자세히 보면 많은 것 을 배 울 수 있 습 니 다.
IjkPlayer소스 코드 획득 및 컴 파일 방법
원본 주소,컴 파일 참조 readme:

#   ijk  
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
#       
cd ijkplayer-android
# checkout     
git checkout -B latest k0.8.0
#     ,      ijk     ,  ffmpeg
./init-android.sh
#   ffmpeg, all        , armv7a
cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
#   ijkplayer,all        , armv7a
cd ..
./compile-ijk.sh all
IjkPlayer 분석 및 수정
Android 버 전의 Ijk Player 예제 프로젝트 에서 재생 영상 인터페이스 는 tv.danmaku.ijk.media.example.activities.VideoActivity 이 며,VideoActivity 에서 Ijk VideoView 를 사용 하여 영상 을 재생 하 는 것 은 tv.danmaku.ijk.media.example.widget.media 가방 에 있 습 니 다.
IjkVideoView 는 안 드 로 이 드 의 VideoView 와 기본적으로 일치 합 니 다.IjkVideoView 에 서 는 비디오 소스 호출 setVideoURI 방법 을 설정 하고 이 방법 은 private 속성의 openVideo 방법 을 호출 합 니 다.openVideo 방법 에 서 는 mSettings.getPlayer()의 값 에 따라 IMediaPlayer 를 만 듭 니 다.

public IMediaPlayer createPlayer(int playerType) {
  IMediaPlayer mediaPlayer = null;
  switch (playerType) {
   case Settings.PV_PLAYER__IjkExoMediaPlayer: {
    IjkExoMediaPlayer IjkExoMediaPlayer = new IjkExoMediaPlayer(mAppContext);
    mediaPlayer = IjkExoMediaPlayer;
   }
   break;
   case Settings.PV_PLAYER__AndroidMediaPlayer: {
    AndroidMediaPlayer androidMediaPlayer = new AndroidMediaPlayer();
    mediaPlayer = androidMediaPlayer;
   }
   break;
   case Settings.PV_PLAYER__IjkMediaPlayer:
   default: {
    IjkMediaPlayer ijkMediaPlayer = null;
    if (mUri != null) {
     ijkMediaPlayer = new IjkMediaPlayer();
     ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
     if (mSettings.getUsingMediaCodec()) {
      ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
      if (mSettings.getUsingMediaCodecAutoRotate()) {
       ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
      } else {
       ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);
      }
      if (mSettings.getMediaCodecHandleResolutionChange()) {
       ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
      } else {
       ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 0);
      }
     } else {
      ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
     }
     //            
    }
    mediaPlayer = ijkMediaPlayer;
   }
   break;
  }
  if (mSettings.getEnableDetachedSurfaceTextureView()) {
   mediaPlayer = new TextureMediaPlayer(mediaPlayer);
  }
  return mediaPlayer;
 }
위의 코드 에서 볼 수 있 듯 이 IjkVideoView 에서 여러 곳 에서 mSettings 를 사 용 했 습 니 다.mSettings 의 값 은 주로 사용자 가 설정 한 것 입 니 다.Shared Preferences 를 통 해 저 장 된 것 은 오디 오 비디오 디 코딩 설정,OpenSLES 사용 여부,렌 더 링 View 등 을 포함 합 니 다.Settings Activity 인터페이스 를 참조 할 수 있 습 니 다.
player Type 에 따라 IjkMediaPlayer 를 만 듭 니 다.앞의 두 가 지 는 구 글 의 ExoPlayer 와 안 드 로 이 드 의 MediaPlayer 입 니 다.그 외 에 도 진정한 Ijk Player 를 만 들 었 습 니 다.
mSettings 의 다른 매개 변 수 는 최종 적 으로 바 뀌 면 IjkMediaPlayer 의 setOption 방법 으로 설정 되 고 IjkMediaPlayer.setOption 은 native 방법 을 직접 호출 합 니 다.IjkMediaPlayer 에 들 어가 면 IjkMediaPlayer 의 많은 방법 이 native 방법 이거 나 native 방법 을 호출 한 것 을 알 수 있 습 니 다.
setGLFilter 인터페이스 추가
ijkmedia 폴 더 에서 전역 검색 방법 중 하나setDataSource,얻 은 내용 은 다음 과 같 습 니 다.

F:\cres\C\ijkplayer-android\ijkmedia\ijkplayer\android\ijkplayer_jni.c:
static void
 IjkMediaPlayer_setDataSourceAndHeaders(
 JNIEnv *env, jobject thiz, jstring path,
 jobjectArray keys, jobjectArray values)
...
static void
IjkMediaPlayer_setDataSourceFd(JNIEnv *env, jobject thiz, jint fd)
{
 MPTRACE("%s
", __func__); ... static void IjkMediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject callback) { MPTRACE("%s
", __func__); ... static JNINativeMethod g_methods[] = { { "_setDataSource", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", (void *) IjkMediaPlayer_setDataSourceAndHeaders }, { "_setDataSourceFd", "(I)V", (void *) IjkMediaPlayer_setDataSourceFd }, { "_setDataSource", "(Ltv/danmaku/ijk/media/player/misc/IMediaDataSource;)V", (void *)IjkMediaPlayer_setDataSourceCallback }, { "_setAndroidIOCallback", "(Ltv/danmaku/ijk/media/player/misc/IAndroidIO;)V", (void *)IjkMediaPlayer_setAndroidIOCallback },
즉,Android 버 전의 ijkplayer 에서 입 구 는 ijkmedia\ijkplayer\\android\ijkplayer 입 니 다.jni.c
Ijk MediaPlayer.java 및 ijkplayerjni.c 파일 에 setGLFilter 를 추가 하 는 방법:

//  setGLFilter  
static void IjkMediaPlayer_native_setGLFilter(JNIEnv *env, jclass clazz,jobject filter)
{
}

// ----------------------------------------------------------------------------
static JNINativeMethod g_methods[] = {
 {
  "_setDataSource",
  "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
  (void *) IjkMediaPlayer_setDataSourceAndHeaders
 },
 { "_setDataSourceFd",  "(I)V",  (void *) IjkMediaPlayer_setDataSourceFd },
 { "_setDataSource",   "(Ltv/danmaku/ijk/media/player/misc/IMediaDataSource;)V", (void *)IjkMediaPlayer_setDataSourceCallback },
 //・・・      
 { "_setGLFilter",   "(Ltv/danmaku/ijk/media/player/IjkFilter;)V", (void *) IjkMediaPlayer_native_setGLFilter },
};
렌 더 링 시 사용자 설정 을 되 돌 리 는 GLFilter 방법
ijkmedia/ijksdl/gles 2/internal.h 파일 에서 IJKGLES2_Renderer 구조 체 내 증가:

typedef struct IJK_GLES2_Renderer
{
 //...
 GLuint frame_buffers[1];
 GLuint frame_textures[1];
 int hasFilter=0;
 void (* func_onCreate)(void);
 void (* func_onSizeChanged)(int width,int height);
 void (* func_onDrawFrame)(int textureId);
 //...
} IJK_GLES2_Renderer;
이 세 가지 방법 은 IjkFlter 의 세 가지 방법 으로 Jni 에서 자바 에 설 치 된 IjkFilter 대상 의 세 가지 방법 을 대응 할 것 입 니 다.
전역 검색 glDraw render.c 에 있 는 IJK 하나만 검색GLES2_Renderer_renderOverlay 방법 에서 렌 더 링 작업 도 이 방법 으로 실 행 됩 니 다.물론 IjkPlayer 는 OpenGLES 렌 더 링 을 이용 할 때 영상 에서 디 코딩 된 데이터 의 구체 적 인 형식 에 따라 렌 더 링 을 한다.예 를 들 어 yuv 420 p,yuv 420 sp,rbg 565 등 여러 형식 이다.구체 적 으로 ijkmedia/ijksdl/gles 2/에서 찾 을 수 있 습 니 다.renderrgb.c\renderer.yuv 420 p.c 등등.
사용자 가 자바 층 에 GLFilter 를 설 정 했 을 때 GLFilter 의 세 가지 방법 은 적당 할 때 C 로 바 뀌 어야 합 니 다.이름 에서 알 수 있 듯 이 이 세 가지 방법 은 GLSurface View.Renderer 인터페이스 에서 정의 한 세 가지 방법 과 같 습 니 다.
구체 적 으로 IJKGLES2_Renderer_renderOverlay 방법의 수정 은 다음 과 같 습 니 다.

GLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
 /*     fitler,       framebuffer,  framebuffer,    
 IjkPlayer       , yuv rgb   ,     texture   ,   
   texture         java     。
 */
 if(renderer->hasFilter&&!renderer->frame_buffers[0]&&renderer->frame_width>0&&renderer->frame_height>0){
  //    texture,               ,       
  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);
  //  framebuffer     ,      
  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);
  // int r;
  // if ((r = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE)
  // {
  //  ALOGE("wuwang: Error in Framebuffer 0x%x", r);
  // }else{
  //  ALOGE("wuwang: glCheckFramebufferStatus 0x%x", r);
  // }
  glBindFramebuffer(GL_FRAMEBUFFER,0);
  //  Java     Filter onCreated   onSizeChanged  
  renderer->func_onCreated();
  renderer->func_onSizeChanged(renderer->frame_width,renderer->frame_height);
  ALOGE("wuwang: create frame_buffers and textures %d,%d",renderer->frame_width,renderer->frame_height);
 }
 //     Filter,   frameBuffer,                  
 if(renderer->hasFilter&&renderer->frame_buffers[0]){
  GLint bindFrame;
  glGetIntegerv(GL_FRAMEBUFFER_BINDING,&bindFrame);
  ALOGE("wuwang: default frame binding %d",bindFrame);
  glBindFramebuffer(GL_FRAMEBUFFER,renderer->frame_buffers[0]);
  // glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,renderer->frame_textures[0],0);
  /*        ,       Filter  ,     GLProgram,         Texture    */
  IJK_GLES2_Renderer_use(renderer);
 }
 if (!renderer || !renderer->func_uploadTexture)
  return GL_FALSE;
 glClear(GL_COLOR_BUFFER_BIT);    IJK_GLES2_checkError_TRACE("glClear");
 ALOGE("wuwang: frame buffer id:%d",renderer->frame_buffers[0]);
 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)){
  if(renderer->hasFilter&&renderer->frame_buffers[0]){
   renderer->func_onSizeChanged(renderer->frame_width,renderer->frame_height);
  }
  renderer->vertices_changed = 0;
  IJK_GLES2_Renderer_Vertices_apply(renderer);
  IJK_GLES2_Renderer_Vertices_reset(renderer);
  IJK_GLES2_Renderer_Vertices_reloadVertex(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);
  IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer);
 }
 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  IJK_GLES2_checkError_TRACE("glDrawArrays");
 //     Filter,     FrameBuffer,   Filter onDrawFrame  。
 if(renderer->hasFilter&&renderer->frame_buffers[0]){
  glBindFramebuffer(GL_FRAMEBUFFER,0);
  renderer->func_onDrawFrame(renderer->frame_textures[0]);
  // renderer->func_onDrawFrame(renderer->plane_textures[0]);
 }
 return GL_TRUE;
}
GLFilter 설정 에서 호출 까지 분석
위 에 완 성 된 인터페이스의 작성 도 잘 되 어 있 습 니 다.이제 인 터 페 이 스 를 전달 하 는 GLFilter 의 세 가지 방법 이 실 행 된 세 가지 방법 과 대응 해 야 사용자 의 Filter 가 진정 으로 역할 을 발휘 할 수 있 습 니 다.
IJK_GLES2_Renderer 의 생 성 은 SDL 에 따 른 것 입 니 다.VoutOverlay 에서 왔 습 니 다.SDL 을 찾 고 있 습 니 다.VoutOverlay 는 어디서 왔 습 니까?ijkmedia/ijksdl/android/ijksdl 을 검색 할 수 있 습 니 다.vout_android_nativewindow.c 의 funccreate_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);
 SDL_UnlockMutex(vout->mutex);
 return overlay;
}
SDL_VoutOverlay 생 성과 SDLVout 관련,SDL 찾기Vout 의 출처 를 찾 을 수 있 습 니 다.
ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c 의 SDLVoutAndroid_CreateForANativeWindow:

SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow()
{
 SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque));
 if (!vout)
  return NULL;
 SDL_Vout_Opaque *opaque = vout->opaque;
 opaque->native_window = NULL;
 if (ISDL_Array__init(&opaque->overlay_manager, 32))
  goto fail;
 if (ISDL_Array__init(&opaque->overlay_pool, 32))
  goto fail;
 opaque->egl = IJK_EGL_create();
 if (!opaque->egl)
  goto fail;
 vout->opaque_class = &g_nativewindow_class;
 vout->create_overlay = func_create_overlay;
 vout->free_l   = func_free_l;
 vout->display_overlay = func_display_overlay;
 return vout;
fail:
 func_free_l(vout);
 return NULL;
}
그것 의 초기 화 는 더 이상 관련 이 없다.그러면 그것 을 호출 할 곳 을 찾 을 수 밖 에 없다.검색 해 보 니 SDLVoutAndroid_Create ForANativeWindow 는 ijkmedia\\ijksdl\android\\ijksdl 에 만 있 습 니 다.vout_android_surface.c 의 SDLVoutAndroid_CreateForAndroidSurface 방법:

SDL_Vout *SDL_VoutAndroid_CreateForAndroidSurface()
{
 return SDL_VoutAndroid_CreateForANativeWindow();
}
가죽 이 한 겹 싸 여 있 는 것 같 으 니 SDL 을 찾 아 보 세 요.VoutAndroid_Create ForAndroidSurface,ijkmedia\\ijkplayer\\android\\ijkplayerandroid.c 의 ijkmpandroid_create 방법:

IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*))
{
 IjkMediaPlayer *mp = ijkmp_create(msg_loop);
 if (!mp)
  goto fail;
 mp->ffplayer->vout = SDL_VoutAndroid_CreateForAndroidSurface();
 if (!mp->ffplayer->vout)
  goto fail;
 mp->ffplayer->pipeline = ffpipeline_create_from_android(mp->ffplayer);
 if (!mp->ffplayer->pipeline)
  goto fail;
 ffpipeline_set_vout(mp->ffplayer->pipeline, mp->ffplayer->vout);
 return mp;
fail:
 ijkmp_dec_ref_p(&mp);
 return NULL;
}
ijkmpandroid_create 는 Ijk Media Player 를 되 돌려 주 었 습 니 다.이것 은 자바 에 도 이런 종류 가 있 습 니 다.그러면 서광 이 멀 지 않 을 것 입 니 다.
ijkmp 재 검색android_create,그 결과 호출 된 것 은 ijkmedia\ijkplayer\\android\ijkplayer 뿐 입 니 다.jni.c 의 IjkMediaPlayernative_setup 방법,여기까지 오 면 Ijk Filter 를 전달 할 수 있 습 니 다.
위의 과정 에서 render.c 에서 jni,IJK 까지 볼 수 있 습 니 다.GLES2_Renderer 의 생 성,SDL 의존VoutOverlay。SDL_VoutOverlay 의 생 성 은 SDL 에 의존 합 니 다.Vout。SDL_Vout 은 FFPlayer 의 멤버 이 고 FFPlayer 는 IjkMediaPlayer 의 멤버 변수 입 니 다.자바 계층 의 IjkMediaPlayer 는 IjkMediaPlayer 에 의존 합 니 다.
GLFilter 에서 IJK 까지GLES2_Renderer
위의 분석 에 따 르 면 jni 에 추 가 된 setGLFilter 의 방법 에서 우 리 는 GLFilter 의 방법 을 IjkMediaPlayer->FFPlayer->SDLVout 에 전달 한 다음 SDL 에 전달 할 수 있 음 을 알 수 있다.VoutOverlay,SDLVoutOverlay 가 IJK 에 게 전달GLES2_Renderer 면 됩 니 다.이렇게 하면 Filter 의 기능 을 증가 시 키 고 IjkPlayer 의 절차 에 영향 을 주지 않 으 며 IOS 역시 GPU 필 터 를 추가 하 는 기능 을 신속하게 실현 할 수 있 습 니 다.
먼저 SDLVoutOverlay 와 SDLVout 의 구조 체 정의 중(ijkmedia/ijksdl/ijksdlvout.h 파일 에)IJKGLES2_Renderer 에 추 가 된 멤버:

struct SDL_VoutOverlay {
 //...
 int hasFilter;
 void (* func_onCreated)(void);
 void (* func_onSizeChanged)(int width,int height);
 int (* func_onDrawFrame)(int textureId);
 //...
};
struct SDL_Vout {
 //...
 int hasFilter;
 void (* func_onCreated)(void);
 void (* func_onSizeChanged)(int width,int height);
 int (* func_onDrawFrame)(int textureId);
 //...
};
그리고 상기 몇 가지 방법 으로 이 몇 명의 구성원 데 이 터 를 각각 SDL 에서 완성 합 니 다.Vout~SDLVoutOverlay,그리고 IJKGLES2_Renderer 의 전달.
각각:
ijkmedia\\ijksdl\\gles 2\\renderer.c 파일 에서 IJKGLES2_Renderer_create 방법

IJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay)
{
 if (!overlay)
  return NULL;
 //    ...
 renderer->format = overlay->format;
 //     
 renderer->hasFilter=overlay->hasFilter;
 renderer->func_onCreated=overlay->func_onCreated;
 renderer->func_onSizeChanged=overlay->func_onSizeChanged;
 renderer->func_onDrawFrame=overlay->func_onDrawFrame;
 return renderer;
}
ijksdl\android\ijksdl_vout_android_nativewindow.c 파일 중 funccreate_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->hasFilter=vout->hasFilter;
 overlay->func_onCreated=vout->func_onCreated;
 overlay->func_onSizeChanged=vout->func_onSizeChanged;
 overlay->func_onDrawFrame=vout->func_onDrawFrame;
 SDL_UnlockMutex(vout->mutex);
 return overlay;
}
마지막 으로 SDL 완성 이 필요 합 니 다.Vout 에 있 는 이 멤버 들 의 값 을 할당 하고 자바 가 들 어 오 는 GLFilter 대상 을 호출 하 는 방법(ijkplayerjni.c 파일 중):

static JNIEnv * mEnv;
static jobject mFilter;
static jmethodID onCreatedMethod;
static jmethodID onSizeChangedMethod;
static jmethodID onDrawFrameMethod;
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)I");
  (*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);
 }
}
int onDrawFrame(int textureId){
 if(onDrawFrameMethod){
  (*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
  int ret=(*mEnv)->CallIntMethod(mEnv,mFilter,onDrawFrameMethod,textureId);
  (*g_jvm)->DetachCurrentThread(g_jvm);
  return ret;
 }
 return textureId;
}
/*        env,filter   onDrawFrame      ,           setGLFilter         */
static void IjkMediaPlayer_native_setGLFilter(JNIEnv *env, jobject clazz, jobject filter)
{
 if(mFilter){
  (*env)->DeleteGlobalRef(env,mFilter);
 }
 IjkMediaPlayer *mp = jni_get_media_player(env, clazz);
 if(filter!=NULL){
  mFilter=(*env)->NewGlobalRef(env,filter);
  mp->ffplayer->vout->hasFilter=1;
  mp->ffplayer->vout->func_onCreated=onCreated;
  mp->ffplayer->vout->func_onSizeChanged=onSizeChanged;
  mp->ffplayer->vout->func_onDrawFrame=onDrawFrame;
 }else{
  mp->ffplayer->vout->hasFilter=0;
 }
}
이로써 자바 는 sdl 의 render 까지 연 결 된 셈 이다.자바 에서 의 처 리 는 GLSurfaceView 설정 Renderer 와 거의 일치 합 니 다.다른 것 은 IjkPlayer 에 추 가 된 GLFilter 는 onDrawFrame 의 매개 변수 로 원본 영상 이미 지 를 제 공 했 습 니 다.GLFilter 에 서 는 이 Texture 를 처리 하고 렌 더 링 만 하면 됩 니 다.
필터 예제 삽입
수 정 된 코드 를 다시 컴 파일 하면 컴 파일 된 라 이브 러 리 는 Ijkplayer 의 Android 프로젝트 에 자동 으로 업 데 이 트 됩 니 다.사용자 정의 필 터 를 설정 하면 의외 의 사고 없 이 효 과 를 볼 수 있 습 니 다.다음은 원본 영상,흑백 필터 처리 후의 영상,AiyaEffectsSDK 를 추가 하고 특수 효 과 를 설정 한 영상 효과 입 니 다.CSDN 이 그림 의 크기 제한 문제 에 대해 모두 한 단락 을 캡 처 했 기 때 문 입 니 다.

공사 가 너무 커서 수정 한 곳 도 많 지 않 아서 코드 를 올 리 지 않 습 니 다.필요 한 친구 가 있 으 면 상기 절차 에 따라 ijkplayer 소스 코드 를 다운로드 하여 스스로 수정 하면 되 며 Ijkplayer 의 소스 코드 도 볼 수 있 습 니 다.
이 편 은 IjkPlayer 가 사용자 정의 GPU 필 터 를 삽입 하 는 방법 을 지원 하 는 것 이 바로 편집장 이 여러분 에 게 공유 하 는 모든 내용 입 니 다.참고 하 시기 바 랍 니 다.많은 응원 부탁드립니다.

좋은 웹페이지 즐겨찾기