ffmpeg源码分析

1: av_open_input_file的简单分析(主要是针对读数据)

int av_open_input_file(AVFormatContext **ic_ptr, const char
*filename,
                       AVInputFormat *fmt,
                       int buf_size,
                       AVFormatParameters *ap)
{
    int err, probe_size;
AVProbeData probe_data, *pd = &probe_data;

//此结构中成员包括:数据操作,缓冲区块等(读取的数据先存入此结构中的缓冲区)
    ByteIOContext *pb = NULL;                       

    pd->filename = "";
    if (filename)
        pd->filename = filename;
    pd->buf = NULL;
    pd->buf_size = 0;

    if (!fmt)
    {
        /* guess format if no file can be opened */
        fmt = av_probe_input_format(pd, 0);
    }

    /* Do not open file if the format does not need it. XXX: specific
       hack needed to handle RTSP/TCP */
    if (!fmt || !(fmt->flags & AVFMT_NOFILE))
    {
        /* if no file needed do not try to open one */
        //根据filename中协议头,准备相应的网络连接,并初始化pb结构体变量
        if ((err=url_fopen(&pb, filename, URL_RDONLY)) < 0)
        {
            goto fail;
        }
        if (buf_size > 0)
        {
            url_setbufsize(pb, buf_size);
        }

        for (probe_size= PROBE_BUF_MIN; probe_size<=PROBE_BUF_MAX && !fmt; probe_size<<=1)
        {
            int score= probe_size < PROBE_BUF_MAX ? AVPROBE_SCORE_MAX/4 : 0;
            /* read probe data */
            pd->buf= av_realloc(pd->buf, probe_size + AVPROBE_PADDING_SIZE);

            //从ByteIOContext中获取数据
            pd->buf_size = get_buffer(pb, pd->buf, probe_size);
            memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE);
            if (url_fseek(pb, 0, SEEK_SET) < 0)
            {
                url_fclose(pb);
                if (url_fopen(&pb, filename, URL_RDONLY) < 0)
                {
                    pb = NULL;
                    err = AVERROR(EIO);
                    goto fail;
                }
            }

            //解析获取的数据
            fmt = av_probe_input_format2(pd, 1, &score);
        }
        av_freep(&pd->buf);
    }

    /* if still no format found, error */
    if (!fmt)
    {
        err = AVERROR_NOFMT;
        goto fail;
    }

    /* check filename in case an image number is expected */
    if (fmt->flags & AVFMT_NEEDNUMBER)
    {
        if (!av_filename_number_test(filename))
        {
            err = AVERROR_NUMEXPECTED;
            goto fail;
        }
}

    err = av_open_input_stream(ic_ptr, pb, filename, fmt, ap);
    if (err)
        goto fail;
    return 0;
fail:
    av_freep(&pd->buf);
    if (pb)
        url_fclose(pb);
    *ic_ptr = NULL;
    return err;

}
(2)网络连接初始化
int url_fopen(ByteIOContext **s, const char *filename, int flags)
{
    URLContext *h;                                //
    int err;
   
//根据filename中协议头,来初始化初始化URLContext变量,并进行
//相应的网络连接
    err = url_open(&h, filename, flags);
    if (err < 0)
        return err;

    //创建并初始化ByteIOContext变量
    err = url_fdopen(s, h);
    if (err < 0)
    {
        url_close(h);
        return err;
    }
    return 0;
}


(3)
int url_open(URLContext **puc, const char *filename, int flags)
{
    URLProtocol *up;
    const char *p;
    char proto_str[128], *q;

    p = filename;
q = proto_str;

//----解析出协议头(如HTTP,TCP)--------//
    while (*p != '/0' && *p != ':')
    {
        /* protocols can only contain alphabetic chars */
        if (!isalpha(*p))
            goto file_proto;
        if ((q - proto_str) < sizeof(proto_str) - 1)
            *q++ = *p;
        p++;
}

    /* if the protocol has length 1, we consider it is a dos drive */
    if (*p == '/0' || is_dos_path(filename))
    {
file_proto:
        strcpy(proto_str, "file");
    }
    else
    {
        *q = '/0';
    }

//遍历URLProtocol全局指针变量链表(这个在av_register_all()中预先
//准备好了), 根据协议头找到对应的协议URLProtocol变量, 再创建并初始化URLContext,然后进行相应的网络连接(如TCP会去连接相应的服务器)
    up = first_protocol;
    while (up != NULL)
    {
        if (!strcmp(proto_str, up->name))
            return url_open_protocol (puc, up, filename, flags);
        up = up->next;
    }
    *puc = NULL;
    return AVERROR(ENOENT);
}
(4)
int url_fdopen(ByteIOContext **s, URLContext *h)
{
    uint8_t *buffer;
    int buffer_size, max_packet_size;

    //设置缓冲块大小(默认值IO_BUFFER_SIZE:32768)
    max_packet_size = url_get_max_packet_size(h);
    if (max_packet_size)
    {
        buffer_size = max_packet_size; /* no need to bufferize more than one packet */
    }
    else
    {
        buffer_size = IO_BUFFER_SIZE;
}

//创建缓冲块
    buffer = av_malloc(buffer_size);
    if (!buffer)
        return AVERROR(ENOMEM);

    //创建ByteIOContext
    *s = av_mallocz(sizeof(ByteIOContext));
    if (!*s)
    {
        av_free(buffer);
        return AVERROR(ENOMEM);
    }

    //初始化ByteIOContext,如缓冲块大小,读写等操作函数指针
    if (init_put_byte(*s, buffer, buffer_size,
                      (h->flags & URL_WRONLY || h->flags & URL_RDWR), h,
                      url_read, url_write, url_seek) < 0)
    {
        av_free(buffer);
        av_freep(s);
        return AVERROR(EIO);
    }
    (*s)->is_streamed = h->is_streamed;
    (*s)->max_packet_size = max_packet_size;
    if (h->prot)
    {
        (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause;
        (*s)->read_seek  = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek;
    }
    return 0;
}


(5) int get_buffer(ByteIOContext *s, unsigned char *buf, int size)
{
    int len, size1;
    size1 = size;
    while (size > 0)
{
    //缓冲块中还没被读取的数据量
        len = s->buf_end - s->buf_ptr;
        if (len > size)
            len = size;
        if (len == 0)
        {
            if (size > s->buffer_size && !s->update_checksum)
            {
                if (s->read_packet)
                    len = s->read_packet(s->opaque, buf, size);
                if (len <= 0)
                {
                    /* do not modify buffer if EOF reached so that a seek back can
                    be done without rereading data */
                    s->eof_reached = 1;
                    if (len<0)
                        s->error= len;
                    break;
                }
                else
                {
                    s->pos += len;
                    size -= len;
                    buf += len;
                    s->buf_ptr = s->buffer;
                    s->buf_end = s->buffer/* + len*/;
                }
            }
            else
            {
                //根据ByteIOContext先初始的成员变量,从文件或网络源获取数据
//后COPY到缓冲块中,实际的操作由先初始化的URLProtocol变量
//中成员方法来完成(如url_read,url_seek等)
                fill_buffer(s);
                len = s->buf_end - s->buf_ptr;
                if (len == 0)
                    break;
            }
        }
        else                                //直接从缓冲中获取数据
        {
            memcpy(buf, s->buf_ptr, len);
            buf += len;
            s->buf_ptr += len;
            size -= len;
        }
    }
    return size1 - size;
}

 

2: http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html 介绍Using libavformat and libavcodec

你可能感兴趣的:(多媒体开发,buffer,url,file,input,protocols,null)