public class DXMediaPlayer extends SurfaceView implements SurfaceHolder.Callback {
...
private native void setSurface(int idx, Surface surface);
...
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(LOG_TAG(), "surface created");
setSurface(mIdx, holder.getSurface());
}
}
ANativeWindow* m_pNativeWindow;
...
JNIEXPORT void JNICALL Java_com_dxmediaplayer_DXMediaPlayer_setSurface(JNIEnv *pEnv, jobject pObj, jint idx, jobject pSurface)
{
if (pSurface != NULL) {
if (!m_pNativeWindow)
m_pNativeWindow = ANativeWindow_fromSurface(pEnv, pSurface);
} else {
if (m_pNativeWindow)
ANativeWindow_release(m_pNativeWindow);
m_pNativeWindow = NULL;
m_nWindowWidth = m_nWindowHeight = 0;
}
}
2. ffmpeg 디코딩 후 Surface 에 복사
ffmpeg 디코딩후 YUV420 -> RGBA 변환(스케일러 사용)후 그대로 복사해주면 된다. 이때 Surface 사이즈에 맞게 스케일링을 할 필요가 없다 (안드로이드에서 스케일링을 해준다)
즉, ffmpeg 스케일러의 sws_getContext 함수에서 소스 사이즈와 데스티네이션 사이즈를 똑같이 AVFrame의 width/height로 해준다(픽셀포멧만 변환)
그리고 아래와같이 Surface에 복사
ANativeWindow_Buffer windowBuffer;
if (ANativeWindow_lock(m_pWindow, &windowBuffer, NULL) < 0) {
DXPRINTF("ANativeWindow_lock failed\n");
} else {
if (windowBuffer.width == windowBuffer.stride) {
memcpy(windowBuffer.bits, pFrame->data, pFrame->size);
} else {
int bpp = GetBitPerPixel(pFrame->pix_fmt)>>3;
int stride = windowBuffer.stride * bpp;
uint8_t *ptr = pFrame->data;
uint8_t *dst = (uint8_t*)windowBuffer.bits;
for (int h=0; h<pFrame->dst_height; h++) {
memcpy(&dst[h*stride], ptr, stride);
ptr += pFrame->dst_width * bpp;
}
}
}
ANativeWindow_unlockAndPost(m_pWindow);
* opengl es (GLSurfaceView) 를 사용할 필요가 없다.