一、引言:
在上一篇博客中,将音频的解码和输出放在了一起分析,文章显得又长又冗杂,考虑到视频渲染及同步也是一个重点分析点,所以这篇博客仅分析视频解码相关的内容。因为ijkplayer和FFmpeg在音频和视频的处理上有很多共用代码,并且在上一篇博客中讲解的足够详细,所以对于视频解码的分析就直接以重点代码来分析了。
二、MediaCodec解码通路分析:
先来看下视频解码相关的通路,ijkplayer有一个option叫“async-init-decoder”
,可以通过上层apk设置到底层中。这个option的含义我不是特别清楚,一般情况下,是没有设置的。所以,在ijkplayer的地方读取该值时为0,即ffp->async_init_decoder
。
下面看一下ijkplayer创建vdec的地方:
stream_component_open@ijkmedia\ijkplayer\ff_ffplay.c:
case AVMEDIA_TYPE_VIDEO:
is->video_stream = stream_index;
is->video_st = ic->streams[stream_index];
/* 通常默认为0,走下面的else */
if (ffp->async_init_decoder) {
...
} else {
/* 初始化 */
decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
/* 打开vdec */
ffp->node_vdec = ffpipeline_open_video_decoder(ffp->pipeline, ffp);
if (!ffp->node_vdec)
goto fail;
}
/* 开启解码 */
if ((ret = decoder_start(&is->viddec, video_thread, ffp, "ff_video_dec")) < 0)
goto out;
is->queue_attachments_req = 1;
/* 这里是关于帧率设置的判断,略过 */
...
break;
如果上面没有主动设置option下来的话,代码中就会走到else中去,首先是decoder_init
,最重要的操作是将packet的queue绑定到解码器中。接下来看下
ffpipeline_open_video_decoder
:
IJKFF_Pipenode* ffpipeline_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{
return pipeline->func_open_video_decoder(pipeline, ffp);
}
pipeline的创建如下:
ijkmp_android_create@ijkmedia\ijkplayer\android\ijkplayer_android.c:
IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*))
{
...
mp->ffplayer->pipeline = ffpipeline_create_from_android(mp->ffplayer);
if (!mp->ffplayer->pipeline)
goto fail;
...
}
找到函数指针的指向:
pipeline->func_open_video_decoder = func_open_video_decoder;
func_open_video_decoder@ijkmedia\ijkplayer\android\ijkplayer_android.c:
static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{
IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
IJKFF_Pipenode *node = NULL;
/* 走Mediacodec的硬解码 */
if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2)
node = ffpipenode_create_video_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout);
/* 走FFmpeg的软解 */
if (!nod