android_media_MediaCodec.cpp源码分析

这里我们来分析和MediaCodec.java对应的native层类:android_media_MediaCodec.cpp的源代码。
在该类的最后,我们会看到这样的代码:

static const JNINativeMethod gMethods[] = {1881    { "native_release", "()V", (void *)android_media_MediaCodec_release },18821883    { "native_reset", "()V", (void *)android_media_MediaCodec_reset },18841885    { "native_releasePersistentInputSurface",1886      "(Landroid/view/Surface;)V",1887       (void *)android_media_MediaCodec_releasePersistentInputSurface},18881889    { "native_createPersistentInputSurface",1890      "()Landroid/media/MediaCodec$PersistentSurface;",1891      (void *)android_media_MediaCodec_createPersistentInputSurface },18921893    { "native_setInputSurface", "(Landroid/view/Surface;)V",1894      (void *)android_media_MediaCodec_setInputSurface },18951896    { "native_enableOnFrameRenderedListener", "(Z)V",1897      (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },18981899    { "native_setCallback",1900      "(Landroid/media/MediaCodec$Callback;)V",1901      (void *)android_media_MediaCodec_native_setCallback },19021903    { "native_configure",1904      "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"1905      "Landroid/media/MediaCrypto;I)V",1906      (void *)android_media_MediaCodec_native_configure },19071908    { "native_setSurface",1909      "(Landroid/view/Surface;)V",1910      (void *)android_media_MediaCodec_native_setSurface },19111912    { "createInputSurface", "()Landroid/view/Surface;",1913      (void *)android_media_MediaCodec_createInputSurface },19141915    { "native_start", "()V", (void *)android_media_MediaCodec_start },1916    { "native_stop", "()V", (void *)android_media_MediaCodec_stop },1917    { "native_flush", "()V", (void *)android_media_MediaCodec_flush },19181919    { "native_queueInputBuffer", "(IIIJI)V",1920      (void *)android_media_MediaCodec_queueInputBuffer },19211922    { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",1923      (void *)android_media_MediaCodec_queueSecureInputBuffer },19241925    { "native_dequeueInputBuffer", "(J)I",1926      (void *)android_media_MediaCodec_dequeueInputBuffer },19271928    { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",1929      (void *)android_media_MediaCodec_dequeueOutputBuffer },19301931    { "releaseOutputBuffer", "(IZZJ)V",1932      (void *)android_media_MediaCodec_releaseOutputBuffer },19331934    { "signalEndOfInputStream", "()V",1935      (void *)android_media_MediaCodec_signalEndOfInputStream },19361937    { "getFormatNative", "(Z)Ljava/util/Map;",1938      (void *)android_media_MediaCodec_getFormatNative },19391940    { "getOutputFormatNative", "(I)Ljava/util/Map;",1941      (void *)android_media_MediaCodec_getOutputFormatForIndexNative },19421943    { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",1944      (void *)android_media_MediaCodec_getBuffers },19451946    { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",1947      (void *)android_media_MediaCodec_getBuffer },19481949    { "getImage", "(ZI)Landroid/media/Image;",1950      (void *)android_media_MediaCodec_getImage },19511952    { "getName", "()Ljava/lang/String;",1953      (void *)android_media_MediaCodec_getName },19541955    { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",1956      (void *)android_media_MediaCodec_setParameters },19571958    { "setVideoScalingMode", "(I)V",1959      (void *)android_media_MediaCodec_setVideoScalingMode },19601961    { "native_init", "()V", (void *)android_media_MediaCodec_native_init },19621963    { "native_setup", "(Ljava/lang/String;ZZ)V",1964      (void *)android_media_MediaCodec_native_setup },19651966    { "native_finalize", "()V",1967      (void *)android_media_MediaCodec_native_finalize },1968};

这些就是在java层和native层代码的一个对应列表。通过下面这个函数,实现natvie方法的注册:

int register_android_media_MediaCodec(JNIEnv *env) {1971    return AndroidRuntime::registerNativeMethods(env,1972                "android/media/MediaCodec", gMethods, NELEM(gMethods));1973}

接下来我们逐次分析MediaCodec各个阶段对应的native方法。首先要看的就是configure方法。

  • configure
static void android_media_MediaCodec_native_configure(956        JNIEnv *env,957        jobject thiz,958        jobjectArray keys, jobjectArray values,959        jobject jsurface,960        jobject jcrypto,961        jint flags) {962    sp codec = getMediaCodec(env, thiz);963964    if (codec == NULL) {965        throwExceptionAsNecessary(env, INVALID_OPERATION);966        return;967    }968969    sp format;970    status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);971972    if (err != OK) {973        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);974        return;975    }976977    sp bufferProducer;978    if (jsurface != NULL) {979        sp surface(android_view_Surface_getSurface(env, jsurface));980        if (surface != NULL) {981            bufferProducer = surface->getIGraphicBufferProducer();982        } else {983            jniThrowException(984                    env,985                    "java/lang/IllegalArgumentException",986                    "The surface has been released");987            return;988        }989    }990991    sp crypto;992    if (jcrypto != NULL) {993        crypto = JCrypto::GetCrypto(env, jcrypto);994    }995996    err = codec->configure(format, bufferProducer, crypto, flags);997998    throwExceptionAsNecessary(env, err);999}1000

通过getMediaCodec方法,获取一个JMediaCodec的强指针codec。如果codec为NULL,就抛出一个INVALID_OPERATION异常。定义AMessage的强引用format,通过ConvertKeyValueArraysToMessage(env, keys, values, &format),将keys和values转换为配置信息,并且将format信息,存储到format中。如果方法返回error,就抛出IllegalArgumentException异常,并且从android_media_MediaCodec_native_configure返回。定义IGraphicBufferProducer的强引用bufferProducer,如果参数jsurface不等于NULL,通过android_view_Surface_getSurface(env, jsurface)获取一个Surface的强引用surface,如果surface不等于NULL,调用surface->getIGraphicBufferProducer(),把返回值赋值给bufferProducer否则,如果surface等于NULL,抛出IllegalArgumentException异常。定义ICrypto的强引用crypto,如果参数jcrypto不为NULL,调用JCrypto::GetCrypto(env, jcrypto),把值返回给crypto。这是针对视频加密的情况。最后,通过codec->configure(format, bufferProducer, crypto, flags)实现对MediaCodec的配置,其中,format,bufferProducer,crypto是之前生成的,flags是传入的参数。上边的调用会返回错误信息,throwExceptionAsNecessary(env, err)会根据返回的具体错误信息,决定是否抛出异常,以及抛出何种异常。

  • start
    下一个阶段是start。
static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {1168    ALOGV("android_media_MediaCodec_start");11691170    sp codec = getMediaCodec(env, thiz);11711172    if (codec == NULL) {1173        throwExceptionAsNecessary(env, INVALID_OPERATION);1174        return;1175    }11761177    status_t err = codec->start();11781179    throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");1180}

通过getMediaCodec(env, thiz)获取JMediaCodec的强引用codec。如果codec为NULL,抛出INVALID_OPERATION异常。调用JMediaCodec的startstatus_t err = codec->start(),根据返回的err的状态,决定是否抛出异常,以及抛出何种异常。

  • dequeueInputBuffer
    下一个状态是dequeueInputBuffer。
static jint android_media_MediaCodec_dequeueInputBuffer(1426        JNIEnv *env, jobject thiz, jlong timeoutUs) {1427    ALOGV("android_media_MediaCodec_dequeueInputBuffer");14281429    sp codec = getMediaCodec(env, thiz);14301431    if (codec == NULL) {1432        throwExceptionAsNecessary(env, INVALID_OPERATION);1433        return -1;1434    }14351436    size_t index;1437    status_t err = codec->dequeueInputBuffer(&index, timeoutUs);14381439    if (err == OK) {1440        return (jint) index;1441    }14421443    return throwExceptionAsNecessary(env, err);1444}

过程基本和start类似,不再详述。值得注意的是这里会返回input buffer的索引。android_media_MediaCodec_dequeueOutputBuffer方法类似,只是返回output buffer的索引。

  • queueInputBuffer
static void android_media_MediaCodec_queueInputBuffer(1235        JNIEnv *env,1236        jobject thiz,1237        jint index,1238        jint offset,1239        jint size,1240        jlong timestampUs,1241        jint flags) {1242    ALOGV("android_media_MediaCodec_queueInputBuffer");12431244    sp codec = getMediaCodec(env, thiz);12451246    if (codec == NULL) {1247        throwExceptionAsNecessary(env, INVALID_OPERATION);1248        return;1249    }12501251    AString errorDetailMsg;12521253    status_t err = codec->queueInputBuffer(1254            index, offset, size, timestampUs, flags, &errorDetailMsg);12551256    throwExceptionAsNecessary(1257            env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());1258}

这里会的调用JMediaCodec的queueInputBuffer,把缓冲区索引index,偏移offset,size,时间戳timestampUs,flags传入,把错误信息回传到errorDetailMsg。

  • flush, stop, reset, release
    实际上,这些操作,都是通过JMediaCodec中对应的方法实现。

更多相关文章

  1. Android之使用bindService启动服务
  2. Android端获取视频第一帧的方法
  3. 第一行代码阅读笔记---详解分析第一个Android程序
  4. Android自定义键盘之汉字键盘
  5. Android实现读取SD卡下所有TXT文件名并用listView显示出来的方法
  6. android 很多应用中用到的 listView + viewPager
  7. android模拟器接收不到UDP数据包解决方法
  8. android,java知识点总结(一)
  9. Android压缩图片到100K以下并保持不失真的高效方法 - feicien的

随机推荐

  1. Android(安卓)Loader 机制浅谈
  2. android 获取MP4文件的图片大小
  3. Android中style和theme巧用:Android应用
  4. android 多表管理查询
  5. 为Android安装BusyBox —— 完整的bash s
  6. 2011的个人总结
  7. android6.0 系统时间不自动校准的问题
  8. Android(安卓)Camera CameraHal.cpp 分析
  9. Android之RecyclerView的局部刷新
  10. {Android} 测试Google Play In-App-Billi