안드로이드 개발 질문/답변
(글 수 45,052)
setDrawingCacheEnabled(true);
buildDrawingCache();
Bitmap bm = getDrawingCache();
이렇게해서 VideoView에서 재생중인 동영상을 캡쳐하려고하는데
getRootView().setdrawingCacheEnabled(true)
getRootView().buildDrawingCache();
는 RootView의 부분만 캡쳐가 가능하던데 VideoView는 캡쳐가 안되더군요
혹시 동영상 재생중에 한 프래임만 Bitmap으로 저장할 수 있는 방법이 있을까요?
2010.06.15 15:00:20
이거 어려운 문제네요.
어떻게 할 수 있나 관심이 있어서 도넛 코드를 좀 살펴봤는데. (다음 버젼들은 어떤지 모르겠네요)
자바만으로는 안 될 것 같습니다.
MediaPlayer.setDisplay() 하게 되면 OpenCore의 경우 PVPlayer에서 Surface의 buffer를 register하고 buffer에다 적고 AndroidSurfaceOutput::writeFrameBuf()를 통해서 Surface로 출력하게 되어 있는 것 같습니다. (opecore밑의 android_surface_output.c에 이렇게 되어 있습니다.)
Surface에 있는 버퍼를 접근하는 API도 자바에 없기 때문에 전혀 방법이 없습니다.
C로도 하는 것도 생각해 봤는데, 명쾌한 방법을 찾지 못 하겠더군요.
끙끙거리며 고민해본 결과 2가지 방법이 가능할 것 같습니다.
이론적인거라 실제로 될지는 모르겠네요. 혹 시간 되시면 한번 해 보시고 결과 알려주세요.
첫번째는 frame buffer를 바로 접근하는 방법입니다. (ADB에서 사용하고 있는 방법이죠)
이 경우는 Frame Buffer를 접근하기 때문에 Screen Capture라서 위에 Dialog 등이 있으면 제대로 안 나오는 문제가 있습니다.
android 소스에서 adb 아래에 보면 framebuffer_service.c 파일이 있는데 이 코드 참고하시면 대충 비슷하게 할 수 있습니다.
타겟마다 다를 수 있을 것 같기는 한데, adb 소스가 변경이 안 되고 사용되는 게 일반적이니 참고 가능하리라 생각됩니다.
아니면 adb service통해서 하는 것도 방법인데 이건 어떻게 하는지 잘 모르겠습니다.
두번째 방법은 확실지는 않지만 JNI를 통해서 Surface 버퍼를 바로 접근할 수 있지 않나 추정되는 부분입니다.
Surface의 JNI 코드 중에 보면 Surface_lockCanvas()가 있습니다. (android_view_surface.cpp)
요 코드 중 일부를 보면
Surface::SurfaceInfo info;
status_t err = surface->lock(&info, &dirtyRegion);
if (err < 0) {
const char* const exception = (err == NO_MEMORY) ?
OutOfResourcesException :
"java/lang/IllegalArgumentException";
doThrow(env, exception, NULL);
return 0;
}
// Associate a SkCanvas object to this surface
jobject canvas = env->GetObjectField(clazz, so.canvas);
env->SetIntField(canvas, co.surfaceFormat, info.format);
SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
SkBitmap bitmap;
bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, info.bpr);
if (info.w > 0 && info.h > 0) {
bitmap.setPixels(info.bits);
} else {
// be safe with an empty bitmap.
bitmap.setPixels(NULL);
}
가 있는데
여기서 info.bits pixel data를 가지는 부분으로 추정됩니다. (코드 상으로 보면 대충 그런 것 같습니다.)
이 가정이 맞다면 요 데이타를 잘 변환만 하면 되겠죠.
간단한 방법이 있는데 확실하지도 않은 복잡한 방법을 야그하는 것 같아 약간 민망하네요.
혹시 뭔가 방법 찾으시면 글 남겨주세요.