总流程图:

1
2
3
4
5
6
7
8
9
10
stream_component_open() ->
ffpipeline_open_video_decoder() ->
func_open_video_decoder() ->
ffpipenode_create_video_decoder_from_android_mediacodec() ->
reconfigure_codec_l() \----> SDL_AMediaFormatJava_createVideoFormat()
\----> create_codec_l() -> SDL_AMediaCodecJava_createByCodecName() ->
\
\----> SDL_AMediaCodec_configure_surface() ->
func_configure_surface()[SDL_AMediaCodecJava_configure_surface()] ->
jmid_configure()[configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags) java]

  1. ff_ffplay.c 中stream_component_open()打开video stream.

  2. 调用
    ffpipeline_open_video_decoder()

  3. 调用
    func_open_video_decoder()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
    {
    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
    IJKFF_Pipenode *node = NULL;

    if (opaque->mediacodec_enabled) //mediacodec_enabled可以在Java代码中设置以开启硬件解码. 由此处进入libstagefright的ACodec
    node = ffpipenode_create_video_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout);
    if (!node) //如果失败则进入ffmpeg的软件解码
    node = ffpipenode_create_video_decoder_from_ffplay(ffp);

    return node;
    }
  4. 首先通过SDL_AMediaFormatJava_createVideoFormat()调用 MediaFormat.java中的createVideoFormat()来配置各种metadata.然后在create_codec_l()中通过
    SDL_AMediaCodecJava_createByCodecName()或者SDL_AMediaCodecJava_createDecoderByType()调用MediaCodec.java的createByCodecName()或者createDecoderByType().
    Media

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
SDL_AMediaFormat *SDL_AMediaFormatJava_createVideoFormat(JNIEnv *env, const char *mime, int width, int height)
{
SDLTRACE("%s", __func__);
jstring jmime = (*env)->NewStringUTF(env, mime);
if (SDL_JNI_CatchException(env) || !jmime) {
return NULL;
}
//调用MediaFormat.java的createVideoFormat(),方便以后给MediaCodec.cpp传递各种在message中的metadata.
jobject local_android_media_format = (*env)->CallStaticObjectMethod(env, g_clazz.clazz, g_clazz.jmid_createVideoFormat, jmime, width, height);
SDL_JNI_DeleteLocalRefP(env, &jmime);
if (SDL_JNI_CatchException(env) || !local_android_media_format) {
return NULL;
}

jobject global_android_media_format = (*env)->NewGlobalRef(env, local_android_media_format);
SDL_JNI_DeleteLocalRefP(env, &local_android_media_format);
if (SDL_JNI_CatchException(env) || !global_android_media_format) {
return NULL;
}

SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque));
if (!aformat) {
SDL_JNI_DeleteGlobalRefP(env, &global_android_media_format);
return NULL;
}

setup_aformat(aformat, global_android_media_format);
//这是一个设置mediaformat的使用例子.由于ACodec.cpp中有一个rotation-degrees描述视频旋转的.由于我们平时用手机竖屏拍摄的视频保存后其实是横向保存的,所以这类视频的rotation不为0.ijkplayer没有将rotation-degrees的值传给ACodec导致视频显示时是按照横向保存的方式显示的.
//这样我们可以使用SDL_AMediaFormat_setInt32(aformat, "rotation-degrees", 90);来纠正视频显示的方向.
SDL_AMediaFormat_setInt32(aformat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, 0);
return aformat;
}