JLayer가 상당히 느린 관계로 libmpg123을 적용해보기로 하였습니다.

MAD에는 저수준의 API가 있어서 ringdroid에 입맞에 맞춰서 적용하는게 손쉬웠지만 libmpg123의 경우에는 저수준의 API함수를 사용하는 예제가 없어서 소스를 훝어보던 차에 *framebyframe*류의 저수준 API함수가 비교적 최근(2009년)에 추가되어 있더군요. 이를 이용하여 libmpg123을 이용한 decoder를 만들어서 넣었고 잘 작둥함을 확인하였습니다. 관련 내용을 검색해봐도 저수준 API 함수를 사용하는 예제는 찾을 수 없었습니다만, 사용방법은 간단하였고 어렵지 않게 적용할 수 있었습니다.

소스는 https://github.com/wkpark/ringdroid master 브렌치에 올려두었습니다~

libmpg123을 사용하는 Mpg123Decoder.c JNI wrapper는 https://github.com/thasmin/android-mp3decoders를 참고하였고, 골격은 MAD에서 사용하던 방식과 거의 같고, readNextFrame() / decodeFrame()등의 저수준 API를 사용하는 부분 등등은 재작성 했습니다.


/* JNI 일부 */ JNIEXPORT float JNICALL Java_com_ringdroid_soundfile_Mpg123Decoder_readNextFrame (JNIEnv *env, jclass c, jlong handle) { MP3File *mp3 = (MP3File*)handle; int err = mpg123_framebyframe_next(mp3->handle); char buf[256]; sprintf(buf, "readNextFrame() err = %d", err); __android_log_write(ANDROID_LOG_INFO, "mp3decode-jni", buf); return err; } JNIEXPORT float JNICALL Java_com_ringdroid_soundfile_Mpg123Decoder_decodeFrame (JNIEnv *env, jclass c, jlong handle) { MP3File *mp3 = (MP3File*)handle; size_t bytes = 0; unsigned char *dummy; int err = mpg123_framebyframe_decode(mp3->handle, NULL, &dummy, &bytes); char buf[256]; sprintf(buf, "decodeFrame() bytes = %d", bytes); __android_log_write(ANDROID_LOG_INFO, "mp3decode-jni", buf); if (err != MPG123_OK) __android_log_write(ANDROID_LOG_INFO, "mp3decode-jni", mpg123_plain_strerror(err)); mp3->leftSamples = bytes / 2; /* buffer는 단지 저장장소일 뿐 실제로 short로 저장되므로 (short *)로 cast해야 하고 실제 데이터 개수는 bytes 수의 1/2 */ mp3->offset = 0; sprintf(buf, "decodeFrame() err = %d", err); __android_log_write(ANDROID_LOG_INFO, "mp3decode-jni", buf); return err != MPG123_OK ? 0 : bytes; } ...

(framebyframe* 저수준 API는 위에서 볼 수 있듯이 매우 간단합니다)

by dumpcookie 2014. 9. 15. 17:44