96

ijkplayer框架简析 -- FFmpeg流程

 5 years ago
source link: http://yydcdut.com/2019/02/03/ijkplayer-ffmpeg-flow/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

读取媒体文件中音视频数据的基本功能

调用逻辑

char filepath[]="bigbuckbunny_480x272.h265";
AVPacket pkt;
int ret = 0;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
int videoindex = -1;

//注册复用器、编码器等
av_register_all();
avformat_network_init();

//打开文件
AVFormatContext *pFormatCtx = avformat_alloc_context();
if(avformat_open_input(&pFormatCtx, filepath, NULL, NULL)!=0){
    return -1;
}
//提取流信息
if(avformat_find_stream_info(pFormatCtx, NULL)<0){
    return -1;
}
//找AVCodec
for(i=0; i<pFormatCtx->nb_streams; i++) {
	if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
		videoindex=i;
		break;
	}
}
if(videoindex==-1) {
	return -1;
}
pCodecCtx=pFormatCtx->streams[videoindex]->codec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL){
	return -1;
}
//开打解码器
if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){
	return -1;
}

//读取音视频数据
while(ret >= 0)
{
  ret = av_read_frame(pFormatCtx, &pkt);
}

av_register_all

作用是注册 codecs``demuxprotocols 。只有调用了该函数,才能使用复用器、编码器等

#define REGISTER_MUXER(X, x)                                            \
    {                                                                   \
        extern AVOutputFormat ff_##x##_muxer;                           \
        if (CONFIG_##X##_MUXER)                                         \
            av_register_output_format(&ff_##x##_muxer);                 \
    }

#define REGISTER_DEMUXER(X, x)                                          \
    {                                                                   \
        extern AVInputFormat ff_##x##_demuxer;                          \
        if (CONFIG_##X##_DEMUXER)                                       \
            av_register_input_format(&ff_##x##_demuxer);                \
    }

#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)

REGISTER_MUXDEMUX(HEVC,hevc);

REGISTER_MUXDEMUX 实际上调用的是 av_register_input_format()av_register_output_format() ,通过这两个方法,将(解)复用器分别添加到了全局变量 first_iformatfirst_oformat 链表的最后位置

void av_register_input_format(AVInputFormat *format)
{
    AVInputFormat **p = last_iformat;

    format->next = NULL;
    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
        p = &(*p)->next;
    last_iformat = &format->next;
}

void av_register_output_format(AVOutputFormat *format)
{
    AVOutputFormat **p = last_oformat;

    format->next = NULL;
    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
        p = &(*p)->next;
    last_oformat = &format->next;
}

avformat_open_input

完成媒体文件的打开和格式探测的功能。方法中调用了 init_input 函数,在这里完成了查找流媒体协议和解复用器的工作

static int init_input(AVFormatContext *s, const char *filename,
                      AVDictionary **options)
{
    int ret;
    ……
    if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
        return ret;

    if (s->iformat)
        return 0;
    return av_probe_input_buffer2(s->pb, &s->iformat, filename,
                                 s, 0, s->format_probesize);
}

s->io_open 实际上调用的就是 io_open_default() ,它最终调用到 url_find_protocol 方法

static const struct URLProtocol *url_find_protocol(const char *filename)
{
    const URLProtocol **protocols;
    ……
    protocols = ffurl_get_protocols(NULL, NULL);
    if (!protocols)
        return NULL;
    for (i = 0; protocols[i]; i++) {
            const URLProtocol *up = protocols[i];
        if (!strcmp(proto_str, up->name)) {
            av_freep(&protocols);
            return up;
        }
        if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
            !strcmp(proto_nested, up->name)) {
            av_freep(&protocols);
            return up;
        }
    }
    av_freep(&protocols);

    return NULL;
}

ffurl_get_protocols() 可以得到当前编译的 FFmpeg 支持的所有流媒体协议,通过 url 的 scheme 和 protocol->name 相比较,得到正确的 protocol

av_probe_input_buffer2() 最终调用到 av_probe_input_format3() , 该方法遍历所有的解复用器,即 first_iformat 链表中的所有节点,调用它们的 read_probe() 函数计算匹配得分,函数最终返回计算找到的最匹配的解复用器


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK