Android多媒體框架(6)—— MediaMuxer的jni代碼分析

MediaMuxer的jni代碼分析

jni方法的定義

MediaMuxer jni方法的定義在frameworks/base/media/jni/android_media_MediaMuxer.cpp中。

static const JNINativeMethod gMethods[] = {

    { "nativeAddTrack", "(J[Ljava/lang/String;[Ljava/lang/Object;)I",
        (void *)android_media_MediaMuxer_addTrack },

    { "nativeSetOrientationHint", "(JI)V",
        (void *)android_media_MediaMuxer_setOrientationHint},

    { "nativeSetLocation", "(JII)V",
        (void *)android_media_MediaMuxer_setLocation},

    { "nativeStart", "(J)V", (void *)android_media_MediaMuxer_start},

    { "nativeWriteSampleData", "(JILjava/nio/ByteBuffer;IIJI)V",
        (void *)android_media_MediaMuxer_writeSampleData },

    { "nativeStop", "(J)V", (void *)android_media_MediaMuxer_stop},

    { "nativeSetup", "(Ljava/io/FileDescriptor;I)J",
        (void *)android_media_MediaMuxer_native_setup },

    { "nativeRelease", "(J)V",
        (void *)android_media_MediaMuxer_native_release },

};

我們逐一看一看這些native方法的源碼。

  • android_media_MediaMuxer_addTrack
static jint android_media_MediaMuxer_addTrack(
        JNIEnv *env, jclass /* clazz */, jlong nativeObject, jobjectArray keys,
        jobjectArray values) {
    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
    if (muxer == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                          "Muxer was not set up correctly");
        return -1;
    }

    sp<AMessage> trackformat;
    status_t err = ConvertKeyValueArraysToMessage(env, keys, values,
                                                  &trackformat);
    if (err != OK) {
        jniThrowException(env, "java/lang/IllegalArgumentException",
                          "ConvertKeyValueArraysToMessage got an error");
        return err;
    }

    // Return negative value when errors happen in addTrack.
    jint trackIndex = muxer->addTrack(trackformat);

    if (trackIndex < 0) {
        jniThrowException(env, "java/lang/IllegalStateException",
                          "Failed to add the track to the muxer");
        return -1;
    }
    return trackIndex;
}

首先,用nativeObject生成一個MediaMuxer(stagefright中,如無特別說明,下同)的強引用計數,如果muxer爲NULL,拋出IllegalStateException。調用ConvertKeyValueArraysToMessage把keys和values數組,轉換爲AMessage的強引用計數trackformat,返回值保存在err中,如果err不等於OK,拋出IllegalArgumentException異常。調用MediaMuxer的addTrack方法,返回值保存在trackIndex中,如果trackIndex小於0,拋出IllegalStateException,返回-1。如果一起正常,就把trackIndex返回。

  • android_media_MediaMuxer_setOrientationHint
static void android_media_MediaMuxer_setOrientationHint(
        JNIEnv *env, jclass /* clazz */, jlong nativeObject, jint degrees) {
    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
    if (muxer == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                          "Muxer was not set up correctly");
        return;
    }
    status_t err = muxer->setOrientationHint(degrees);

    if (err != OK) {
        jniThrowException(env, "java/lang/IllegalStateException",
                          "Failed to set orientation hint");
        return;
    }

}

用nativeObject生成一個MediaMuxer的強引用計數,如果muxer爲NULL,拋出IllegalStateException。調用MediaMuxer的setOrientationHint,並且結果保存在err中,拋出IllegalStateException。
start,stop,setLocation的定義和setOrientationHint類似。

  • android_media_MediaMuxer_native_setup
static jlong android_media_MediaMuxer_native_setup(
        JNIEnv *env, jclass clazz, jobject fileDescriptor,
        jint format) {
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    ALOGV("native_setup: fd %d", fd);

    MediaMuxer::OutputFormat fileFormat =
        static_cast<MediaMuxer::OutputFormat>(format);
    sp<MediaMuxer> muxer = new MediaMuxer(fd, fileFormat);
    muxer->incStrong(clazz);
    return reinterpret_cast<jlong>(muxer.get());
}

根據參數fileDescriptor,獲取一個文件描述符fd,輸出文件格式就是參數foramt指定的格式。根據fd和format創建MediaMuxer的實例muxer,增加muxer的強引用計數。

  • android_media_MediaMuxer_writeSampleData
static void android_media_MediaMuxer_writeSampleData(
        JNIEnv *env, jclass /* clazz */, jlong nativeObject, jint trackIndex,
        jobject byteBuf, jint offset, jint size, jlong timeUs, jint flags) {
    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
    if (muxer == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                          "Muxer was not set up correctly");
        return;
    }

    // Try to convert the incoming byteBuffer into ABuffer
    void *dst = env->GetDirectBufferAddress(byteBuf);

    jlong dstSize;
    jbyteArray byteArray = NULL;

    if (dst == NULL) {

        byteArray =
            (jbyteArray)env->CallObjectMethod(byteBuf, gFields.arrayID);

        if (byteArray == NULL) {
            jniThrowException(env, "java/lang/IllegalArgumentException",
                              "byteArray is null");
            return;
        }

        jboolean isCopy;
        dst = env->GetByteArrayElements(byteArray, &isCopy);

        dstSize = env->GetArrayLength(byteArray);
    } else {
        dstSize = env->GetDirectBufferCapacity(byteBuf);
    }

    if (dstSize < (offset + size)) {
        ALOGE("writeSampleData saw wrong dstSize %lld, size  %d, offset %d",
              (long long)dstSize, size, offset);
        if (byteArray != NULL) {
            env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
        }
        jniThrowException(env, "java/lang/IllegalArgumentException",
                          "sample has a wrong size");
        return;
    }

    sp<ABuffer> buffer = new ABuffer((char *)dst + offset, size);

    status_t err = muxer->writeSampleData(buffer, trackIndex, timeUs, flags);

    if (byteArray != NULL) {
        env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
    }

    if (err != OK) {
        jniThrowException(env, "java/lang/IllegalStateException",
                          "writeSampleData returned an error");
    }
    return;
}

GetDirectBufferAddress獲取byteBuf的共享內存地址dst,如果dst爲NULL,CallObjectMethod(byteBuf, gFields.arrayID)調用java/nio/ByteBuffer中的array方法,嘗試獲取byteArray,如果byteArray依然爲NULL,拋出IllegalArgumentException,返回。獲取byteArray中的elements和byteArray的長度。如果之前獲取的dst不爲NULL,直接獲取byteBuf的容量。如果dstSize小於offset加size的和,拋出IllegalArgumentException,如果byteArray不爲空,需要釋放它,返回。調用MediaMuxer類的writeSampleData方法。

  • android_media_MediaMuxer_native_release
static void android_media_MediaMuxer_native_release(
        JNIEnv* /* env */, jclass clazz, jlong nativeObject) {
    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
    if (muxer != NULL) {
        muxer->decStrong(clazz);
    }
}

減少muxer的強引用計數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章