美文网首页ijkplayer
ijkplayer 视频解码线程

ijkplayer 视频解码线程

作者: ce0b74704937 | 来源:发表于2018-06-06 20:38 被阅读0次

ijkplayer 读线程中说过,ijkplayer主要创建了三个线程,一个是音频输出线程,一个是音频解码线程,一个是视频解码线程,它们都是在ff_ffplay.c/stream_component_open()完成的

跟一下video_thread()代码如下

static int video_thread(void *arg)
{
    FFPlayer *ffp = (FFPlayer *)arg;
    int       ret = 0;

    if (ffp->node_vdec) {
        ret = ffpipenode_run_sync(ffp->node_vdec);
    }
    return ret;
}

可以看出视频解码线程,最终调用函数ffpipenode_run_sync(),该函数指针的赋值在ff_ffpipeline.c/func_open_video_decoder()中完成(而func_open_video_decoder函数的赋值同func_open_audio_output函数都在ffpipeline_create_from_android赋值),在ff_ffpipeline.c/func_open_video_decoder()中会判断使用硬件解码(硬解)还是软件解码(软解)

软解代码较好跟,所以下面重点说一下硬解的流程,如果是硬解ff_ffpipeline.c/func_open_video_decoder()会调用ffpipenode_create_video_decoder_from_android_mediacodec(),该函数里面会给ffpipenode_run_sync函数指针赋值,说明在硬解情况下,video_thread()中调用ffpipenode_run_sync()最终是调用了ffpipenode_android_mediacodec_vdec.c/ffpipenode_run_sync(),其主要代码如下

static int func_run_sync(IJKFF_Pipenode *node)
{
    ...
    opaque->enqueue_thread = SDL_CreateThreadEx(&opaque->_enqueue_thread, enqueue_thread_func, node, "amediacodec_input_thread");
    ...
    while (!q->abort_request) {
        ...
        ret = drain_output_buffer(env, node, timeUs, &dequeue_count, frame, &got_frame);
        ...
    }
    ...
}

ffpipenode_android_mediacodec_vdec.c/ffpipenode_run_sync()干了两件事:

  1. 调用SDL_CreateThreadEx("amediacodec_input_thread")又创建了一个新的线程,干嘛用的待会说
  2. 调用drain_output_buffer函数

1. 调用SDL_CreateThreadEx(..., enqueue_thread_func, ..., "amediacodec_input_thread")
该线程命名叫amediacodec_input_thread,可以猜测它应该是将待解码视频帧推入硬解解码器的,该线程里调用了feed_input_buffer()函数,该函数主要代码如下

static int feed_input_buffer(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *enqueue_count)
{
    ...
    if (d->pkt_temp.data) {
        ...
        queue_flags = 0;
        input_buffer_index = SDL_AMediaCodec_dequeueInputBuffer(opaque->acodec, timeUs);
        if (input_buffer_index < 0) {
            ...
        } else {
            ...
            copy_size = SDL_AMediaCodec_writeInputData(opaque->acodec, input_buffer_index, d->pkt_temp.data, d->pkt_temp.size);
            ...
        }
        ...
        // ALOGE("queueInputBuffer, %lld\n", time_stamp);
        amc_ret = SDL_AMediaCodec_queueInputBuffer(opaque->acodec, input_buffer_index, 0, copy_size, time_stamp, queue_flags);
        ...
    }
    ...
}

feed_input_buffer中先是调用SDL_AMediaCodec_dequeueInputBuffer()获取输入buffer的地址,然后调用SDL_AMediaCodec_writeInputData()将待解码视频帧输入buffer里,最后调用SDL_AMediaCodec_queueInputBuffer()将buffer的数据送给解码器解码

可以看出新创建出的线程实际就是将数据塞入硬件解码器中

2. 调用drain_output_buffer函数
drain_output_buffer函数调用ffpipenode_android_mediacodec_vdec.c/drain_output_buffer_l()函数

static int drain_output_buffer_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, int *got_frame)
{
    ...
    output_buffer_index = SDL_AMediaCodecFake_dequeueOutputBuffer(opaque->acodec, &bufferInfo, timeUs);
    ...
    ret = amc_fill_frame(...)
    ...
}

ffpipenode_android_mediacodec_vdec.c/drain_output_buffer_l()先调用SDL_AMediaCodecFake_dequeueOutputBuffer()获取output buffer中解码好的数据地址,然后调用amc_fill_frame将解码后的视频帧取出

到这里视频解码线程就做完了,软解类似

这部分还有致谢同事东升同学和江月同学给的指导,哈哈

相关文章

  • ijkplayer 视频解码线程

    在ijkplayer 读线程中说过,ijkplayer主要创建了三个线程,一个是音频输出线程,一个是音频解码线程,...

  • ijkplayer 音频解码线程

    在ijkplayer 读线程中提到,函数stream_component_open()中的decoder_star...

  • ijkplayer 视频播放线程

    在ijkplayer 读线程中提到,stream_open()会创建读线程和视频渲染线程,甚至可以说视频渲染线程要...

  • ijkplayer系列(五) —— ijkplayer视频解码与

    写在前面 前几篇文章从播放器初始化一直分析到了音频播放,其实从中基本能发现作者写ijkplayer的思路的。所以分...

  • 视屏的软解码和硬解码

    最近在研究IJKPlayer框架,对视屏的软解码和硬解码也有一些自己的理解. 我们在计算机上播放的视频文件都是经过...

  • 31_音视频播放器_音频解码

    一、简介 如上图,我们在主线程中开启一个子线程进行解封装,然后在开两个线程分别进行视频解码和音频解码,其中音频解码...

  • ijkplayer学习笔记(五)——视频解码

    ijkplayer在视频解码上支持软解和硬解两种方式,可在起播前配置优先使用的解码方式,播放过程中不可切换。iOS...

  • Unity渲染iOS中的NV12格式数据---(上)

    在我们的项目中,iOS端视频播放使用的是第三方开源框架ijkplayer,在硬解码的时候,解码出的数据格式是NV1...

  • 用ijkplayer播放视频源

    1、简介 ijkplayer是b站开源的超级好用的视频播放器,支持多种视频的硬解码,使用起来简单方面,并且Andr...

  • ijkplayer 读线程

    在ijkplayer初始化流程中的结尾提到,stream_open()会创建读线程和视频渲染线程,下面是strea...

网友评论

    本文标题:ijkplayer 视频解码线程

    本文链接:https://www.haomeiwen.com/subject/ztsisftx.html