이 글은 기존 운영했던 WordPress 블로그인 PyxisPub: Development Life (pyxispub.uzuki.live) 에서 가져온 글 입니다. 모든 글을 가져오지는 않으며, 작성 시점과 현재 시점에는 차이가 많이 존재합니다.
작성 시점: 2020-06-01
이 글은 아래 글의 후속이다.
Android MediaCodec, MediaMuxer 살펴보기
작업을 하다 보니까, 하위 버전에서 오래 걸리는 문제가 있어 고민하던 차에 'ndk를 이용해 cpp로 작업하면 좀 더 빠르지 않을까?' 하는 생각이 있었다.
일단, 결론은 다음과 같다.
이러한 이유 때문에 실제로 도입은 못했지만, 그래도 어느정도 매칭은 가능해서 사용이 가능했었고, 몇 가지 겪었던 문제를 소개하고자 한다.
MediaExtractor에 설정할 때, FileDescriptor 로 통해 설정하는 경우가 있다.
먼저, FileDescriptor를 파라미터에 선언한다.
external fun convert(input: FileDescriptor, inLength: Long, output: FileDescriptor, outLength: Long)
이에 대한 JNI Header는 다음과 같다.
extern "C"
JNIEXPORT jint JNICALL
Java_com_github_windsekirun_***_***_convert(JNIEnv *env, jobject thiz,
jobject input,
jlong inLength,
jobject output,
jlong outLength)
FileDescriptor 는 jobject
로 매칭되는데, 이를 FileDescriptor
(정확히는 FileDescriptor.descriptor
) 로 변환하려면 아래와 같은 코드를 사용한다.
static int jniGetFDFromFileDescriptor(JNIEnv * env, jobject fileDescriptor) {
jint fd = -1;
jclass fdClass = env->FindClass("java/io/FileDescriptor");
if (fdClass != NULL) {
jfieldID fdClassDescriptorFieldID = env->GetFieldID(fdClass, "descriptor", "I");
if (fdClassDescriptorFieldID != NULL && fileDescriptor != NULL) {
fd = env->GetIntField(fileDescriptor, fdClassDescriptorFieldID);
}
}
return fd;
}
마지막으로, 얻은 FileDescriptor는 아래와 같이 설정한다.
AMediaExtractor *extractor = AMediaExtractor_new();
media_status_t amresult = AMediaExtractor_setDataSourceFd(extractor, inputFd, 0, inLength);
if (amresult != AMEDIA_OK) {
LOGE("Error setting extractor data source, err %d", amresult);
return -1;
}
여기서 media_status_t 는 NdkMediaError.h
에 선언되어 있다. (https://cs.android.com/android/platform/superproject/+/master:frameworks/av/media/ndk/include/media/NdkMediaError.h;l=43?q=NdkMediaError.h)
지난 글에서는 setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
로 설정했었는데, NDK에서는 아래와 같이 사용한다.
AMediaFormat *outputFormat = AMediaFormat_new();
AMediaFormat_setInt32(outputFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, 2130708361);
여기서 2130708361
는 MediaCodecInfo.CodecCapabilities
에 선언되어 있는 COLOR_FormatSurface
의 값이다. (https://cs.android.com/android/platform/superproject/+/master:frameworks/base/media/java/android/media/MediaCodecInfo.java;l=218?q=CodecCapabilities)
이 것이 도입을 하지 못하게 했었던 'API 26' 문제 중 하나인데, surface = encoder.createInputSurface()
에 대응되는 아래 코드가 API 26부터 사용이 가능했다.
ANativeWindow *surface;
AMediaCodec_createInputSurface(encoder, &surface);
media_status_t decoderConfigure = AMediaCodec_configure(decoder, inFormat, surface, nullptr, 0);
Backport 되어 있는 것이 있는지 찾지는 못했지만, 위와 같이 사용할 수 있다.
encoder.signalEndOfInputStream()
에 대응되는 코드인 AMediaCodec_signalEndOfInputStream(encoder);
가 API 26부터 사용이 가능했다.
설명상으로는 Equivalent to submitting an empty buffer with AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM set
로 되어있어, encoder의 inputBuffer에 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM
를 설정하면 될 것 같아서 시도해 보았지만, sf MediaCodecError -38
이라는 오류가 나오는 것 같았다.
이 것도 위와 마찬가지로 적절한 해결 방법을 찾지 못했다.