리눅스 & 안드로이드2011. 2. 26. 20:13
제목이 좀 모호하다. 그치?ㅋ 어제 오늘 이놈 땜에 삽질을 좀 했다.
Daum 비디오 플레이어를 따라 만들어 보려고 마음먹고, 산후조리원에서 맥북으로 관련 자료들을 좀 찾아 보았다.

우선 가장 필요한 것이, 비디오에서 특정 시간의 frame을 bitmap으로 꺼내 오는것!
와이프의 도움으로 MediaMetadataRetriever class를 이용하면 된다는 것을 알게 되었고,
Android Developer 사이트에서 위의 class를 찾아 보니 과연 getFrameAtTime method가 있었다!(얏호!)

"이 method를 가지고 작업을 시작하면 되겠네~"라고 생각하고 즐겁게 출근하여,
실제 sample code를 만들어보던 중에 1차 벽에 부딛치게 된다.

MediaMetadataRetriever가 @hide 속성이 있어서 SDK로 publishing 되지 않았던 것!
하지만 이때 까지만 해도 "왜 Android Developer 사이트에 보이는 API가 @hide로 되어 있을까? API Level이 다른가?"라는 의심은 하지도 못했고, 당연히 다음에 부딛칠 벽도 예상할 수 없었다.

하지만 바로 다음 문제에 봉착!
내가 작업하는 환경은 API Level 8. getFrameAtTime의 API Level 10! API Level 10!! API Level 10!!!
정말 난감한 상황이었다. -_-;
부랴부랴 API Level 10에 대해 찾아보니, Android 2.3.3에 해당했다.
2.3 Gingerbread에 대해서만 알고 있었는데 2.3.3은 도대체 뭐냐고!!!!
Android GitWeb에서 2.3.3을 입수하고 나서야 소스에서 확인할 수 있었다.(@hide도 제거되어 publishing SDK가 됨)
여기서부터 다시 삽질이 시작되었던 것이었던 것이었다;;
어디서도 Android 2.3.3이 올라간 device를 구할 수 없었고, emulator는 너무 느렸다.
그래서 오기로 2.3.3에 있는 MediaMetadataRetriever 관련 코드들을 포팅 해 보겠다고 마음 먹어버렸다.(왜! -_-;)
그러나 역시나 포팅은 힘들었다. 제대로 알고 하는게 아니었기 때문.
에러 하나를 수정하면 또 몇 개가 나오고. 이것의 무한 반복. 하고 나서도 제대로 된다는 보장도 없었다.
결국 빌드까지는 완료 하였지만, HAL(Hardware Abstraction Layer)관련 코드 간과하고 있었고, 잘 되지 않았다;;

여기서 접기에는 좀 아쉬운 감이 있었다.(무려 하루를 투자 하였으니...-0-)
그래서 코드를 조금 더 살펴보던 중, HAL 코드에서 특정 frame을 꺼내오는 함수를 발견!
"좋아! 그럼 이 함수를 가지고 내가 한번 만들어 보지 뭐!" 라고 생각하고 토요일 특근을 결심!!!

수빈이 B.C.G. 접종을 위해 소아과를 다녀오느라 늦으막히(오전 10시 53분) 특근을 찍고 작업을 시작했다.
JAVA, JNI, 각종 C++ 소스파일들, 그리고 HAL 관련 소스파일들에 모조리 코딩을 했고 빌드에 성공!
두근두근 마음을 졸이며 실행을 해 보았으나 잘 되지 않았고, 문제는 점점 미궁으로 빠져들어갔다.
처음에는 captureFrame과 같은 결과를 뱉어 내더니, 나중에는 아무런 Bitmap도 뱉어내지 않았던 것이다.

도대체 무엇이 문제일까 찾고 또 찾아보았지만 전혀 알 수 없었고, 무식한 방법(디버그 메시지를 추가하고 빌드하여 다운로드후 실행-이것의 무한반복)으로 특정 method가 무조건 NULL을 뱉어내는 느낌을 받고 확인해본 결과, abstract class를 구현 해 놓은 class(실은 껍데기. 모두 NULL을 반환하도록 되어 있음) method argument type과 이를 상속한 실제 구현(HAL)부의 method의 argument type이 서로 다르게 해석되어 계속해서 껍데기 class의 method를 호출한다는걸 발견하고 너무 허탈했다.

요는 Android 2.3.3의 코드를 참조하다가 long을 int64_t로 선언되어 있는것을 발견하고 모두 바꿔주었는데, 이것이 화근이었다. long은 C/C++ native type이므로 어디서든 동일하게 해석되지만, int64_t는 framework과 HAL에서 서로 다르게 해석되었던것. 같이 빌드되는 소스인데도 이렇게 달라서야-_-;

그래서 모두 long으로 바꿔주니 호출은 제대로 이루어 졌으나, 꺼내오는 프레임은 항상 7초 언저리.
분명 시간을 입력으로 전달하는데도 그래서 이상하다는 생각이 들었고, HAL 관련 코드를 좀더 살펴보니 우습게도(왜 이렇게 코드를 작성 해 놨는지 정말 궁금!) 입력되는 시간은 무시하고, thumbnail seek time(아마도 미리 정의 되어 있는 듯)을 가져와서 해당 시간 위치에서 frame을 꺼내 오도록 코드가 작성되어 있었다.

이 부분을 제거하고 다시 빌드! 다운로드! 그리고 실행...
푸하하하하하하하~!!!!! 드디어 원하는 시간에서 frame을 꺼내올 수 있게 되었다!

이제 퇴근해야겠다. 마트에 들러 젖병세정제와 젖병솔을 사고 수빈이를 보러가야겠다~
아 행복해~~~

Posted by 세월의돌
리눅스 & 안드로이드2011. 2. 24. 17:04
 Android framework source에 보면 분명 public으로 지정된 class, method, variable인데 @hide attribute가 붙어있어 SDK로는 접근이 불가능한 요소들이 존재한다. 분명 뭔가 이유가 있기 때문에 Google에서 그렇게 막아 놓았을 수도있다.(본인들만 편리하게 사용하려고 그랬을 수도 있음-_-;)

 그러나 이클립스Eclipse에서 응용프로그램을 개발하다 보면, 때로는 필요한 상황이 발생할 수 있다. 그럴때 발생하는 어려움을 해결할 수 있는 방법이 있었던 것 같다. (내가 모르고 있었으므로...^^;)

 방법은 아주 간단(?)했다. 필요한 프레임웍 JAVA 소스의 패키지 디렉토리 구조를 그대로 본인의 프로젝트 디렉토리에 생성 후 복사 해 주면 된다. 즉,

MediaPlayer.java가 필요하다면, MediaPlayer.java의 패키지가 android.media이므로, 본인의 (project directory)/src/android/media/MediaPlayer.java 처럼 복사하면 된다.

'리눅스 & 안드로이드' 카테고리의 다른 글

MediaController 초기화 과정  (0) 2011.03.07
getFrameAtTime을 위한 삽질  (2) 2011.02.26
안드로이드 SD card 마운트(vold)  (1) 2011.02.17
Kernel Command Line  (0) 2011.02.15
GNU Compiler __attribute__  (2) 2011.02.11
Posted by 세월의돌